summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.nuget/NuGet.Config6
-rw-r--r--.nuget/NuGet.exebin0 -> 1655808 bytes
-rw-r--r--BouncyCastle-PCL.sln26
-rw-r--r--Crypto/Contributors.html116
-rw-r--r--Crypto/License.html39
-rw-r--r--Crypto/Readme.html455
-rw-r--r--Crypto/bzip2/src/BZip2Constants.cs103
-rw-r--r--Crypto/bzip2/src/CBZip2InputStream.cs919
-rw-r--r--Crypto/bzip2/src/CBZip2OutputStream.cs1696
-rw-r--r--Crypto/bzip2/src/CRC.cs134
-rw-r--r--Crypto/crypto.csproj3469
-rw-r--r--Crypto/doc/crypto.xml19296
-rw-r--r--Crypto/doc/wp7/crypto.xml19296
-rw-r--r--Crypto/src/AssemblyInfo.cs82
-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.cs232
-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.cs27
-rw-r--r--Crypto/src/asn1/Asn1InputStream.cs339
-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.cs26
-rw-r--r--Crypto/src/asn1/Asn1Sequence.cs255
-rw-r--r--Crypto/src/asn1/Asn1Set.cs326
-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.cs121
-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.cs90
-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.cs110
-rw-r--r--Crypto/src/asn1/DerEnumerated.cs100
-rw-r--r--Crypto/src/asn1/DerGeneralString.cs81
-rw-r--r--Crypto/src/asn1/DerGeneralizedTime.cs305
-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.cs242
-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.cs85
-rw-r--r--Crypto/src/asn1/DerSet.cs108
-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/DerUnknownTag.cs80
-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.cs166
-rw-r--r--Crypto/src/asn1/LazyASN1InputStream.cs33
-rw-r--r--Crypto/src/asn1/LazyDERSequence.cs82
-rw-r--r--Crypto/src/asn1/LazyDERSet.cs82
-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.cs231
-rw-r--r--Crypto/src/asn1/cms/Attributes.cs43
-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.cs18
-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.cs83
-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.cs167
-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.cs66
-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.cs85
-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/SignedData.cs282
-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.cs175
-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.cs64
-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.cs48
-rw-r--r--Crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs179
-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.cs138
-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.cs106
-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.csbin0 -> 20844 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.cs102
-rw-r--r--Crypto/src/asn1/nist/NISTObjectIdentifiers.cs61
-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.cs80
-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.cs61
-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.cs126
-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.cs131
-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.cs163
-rw-r--r--Crypto/src/asn1/pkcs/SignerInfo.cs154
-rw-r--r--Crypto/src/asn1/sec/ECPrivateKeyStructure.cs118
-rw-r--r--Crypto/src/asn1/sec/SECNamedCurves.cs1192
-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.cs128
-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.cs428
-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.cs378
-rw-r--r--Crypto/src/asn1/util/Dump.cs30
-rw-r--r--Crypto/src/asn1/util/FilterStream.cs72
-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.cs110
-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.cs73
-rw-r--r--Crypto/src/asn1/x509/AuthorityInformationAccess.cs105
-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/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.cs131
-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.cs118
-rw-r--r--Crypto/src/asn1/x509/NoticeReference.cs138
-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.cs70
-rw-r--r--Crypto/src/asn1/x509/PolicyQualifierId.cs28
-rw-r--r--Crypto/src/asn1/x509/PolicyQualifierInfo.cs91
-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.cs142
-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.cs120
-rw-r--r--Crypto/src/asn1/x509/UserNotice.cs104
-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.cs125
-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.cs129
-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.cs451
-rw-r--r--Crypto/src/asn1/x509/X509ExtensionsGenerator.cs81
-rw-r--r--Crypto/src/asn1/x509/X509Name.cs1189
-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/KeySpecificInfo.cs58
-rw-r--r--Crypto/src/asn1/x9/OtherInfo.cs88
-rw-r--r--Crypto/src/asn1/x9/X962NamedCurves.cs733
-rw-r--r--Crypto/src/asn1/x9/X962Parameters.cs53
-rw-r--r--Crypto/src/asn1/x9/X9Curve.cs147
-rw-r--r--Crypto/src/asn1/x9/X9ECParameters.cs170
-rw-r--r--Crypto/src/asn1/x9/X9ECParametersHolder.cs22
-rw-r--r--Crypto/src/asn1/x9/X9ECPoint.cs44
-rw-r--r--Crypto/src/asn1/x9/X9FieldElement.cs69
-rw-r--r--Crypto/src/asn1/x9/X9FieldID.cs102
-rw-r--r--Crypto/src/asn1/x9/X9IntegerConverter.cs48
-rw-r--r--Crypto/src/asn1/x9/X9ObjectIdentifiers.cs135
-rw-r--r--Crypto/src/bcpg/ArmoredInputStream.cs517
-rw-r--r--Crypto/src/bcpg/ArmoredOutputStream.cs333
-rw-r--r--Crypto/src/bcpg/BcpgInputStream.cs359
-rw-r--r--Crypto/src/bcpg/BcpgObject.cs22
-rw-r--r--Crypto/src/bcpg/BcpgOutputStream.cs394
-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.cs80
-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.cs115
-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.cs20
-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.cs86
-rw-r--r--Crypto/src/bcpg/UserAttributeSubpacketTags.cs10
-rw-r--r--Crypto/src/bcpg/UserAttributeSubpacketsReader.cs63
-rw-r--r--Crypto/src/bcpg/UserIdPacket.cs37
-rw-r--r--Crypto/src/bcpg/attr/ImageAttrib.cs68
-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.cs63
-rw-r--r--Crypto/src/bcpg/sig/RevocationKeyTags.cs9
-rw-r--r--Crypto/src/bcpg/sig/RevocationReason.cs60
-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.cs25
-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.cs156
-rw-r--r--Crypto/src/cms/CMSAuthenticatedDataParser.cs214
-rw-r--r--Crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs275
-rw-r--r--Crypto/src/cms/CMSAuthenticatedGenerator.cs35
-rw-r--r--Crypto/src/cms/CMSCompressedData.cs107
-rw-r--r--Crypto/src/cms/CMSCompressedDataGenerator.cs66
-rw-r--r--Crypto/src/cms/CMSCompressedDataParser.cs57
-rw-r--r--Crypto/src/cms/CMSCompressedDataStreamGenerator.cs144
-rw-r--r--Crypto/src/cms/CMSContentInfoParser.cs47
-rw-r--r--Crypto/src/cms/CMSEnvelopedData.cs115
-rw-r--r--Crypto/src/cms/CMSEnvelopedDataGenerator.cs178
-rw-r--r--Crypto/src/cms/CMSEnvelopedDataParser.cs161
-rw-r--r--Crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs285
-rw-r--r--Crypto/src/cms/CMSEnvelopedGenerator.cs331
-rw-r--r--Crypto/src/cms/CMSEnvelopedHelper.cs311
-rw-r--r--Crypto/src/cms/CMSException.cs25
-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.cs57
-rw-r--r--Crypto/src/cms/CMSProcessableInputStream.cs52
-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.cs551
-rw-r--r--Crypto/src/cms/CMSSignedDataParser.cs455
-rw-r--r--Crypto/src/cms/CMSSignedDataStreamGenerator.cs917
-rw-r--r--Crypto/src/cms/CMSSignedGenerator.cs261
-rw-r--r--Crypto/src/cms/CMSSignedHelper.cs319
-rw-r--r--Crypto/src/cms/CMSStreamException.cs26
-rw-r--r--Crypto/src/cms/CMSTypedStream.cs72
-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.cs124
-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.cs226
-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/NullOutputStream.cs20
-rw-r--r--Crypto/src/cms/OriginatorId.cs51
-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.cs259
-rw-r--r--Crypto/src/crypto/BufferedAsymmetricBlockCipher.cs152
-rw-r--r--Crypto/src/crypto/BufferedBlockCipher.cs378
-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.cs25
-rw-r--r--Crypto/src/crypto/DataLengthException.cs39
-rw-r--r--Crypto/src/crypto/IAsymmetricBlockCipher.cs30
-rw-r--r--Crypto/src/crypto/IAsymmetricCipherKeyPairGenerator.cs24
-rw-r--r--Crypto/src/crypto/IBasicAgreement.cs24
-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.cs37
-rw-r--r--Crypto/src/crypto/KeyGenerationParameters.cs55
-rw-r--r--Crypto/src/crypto/MaxBytesExceededException.cs29
-rw-r--r--Crypto/src/crypto/PbeParametersGenerator.cs190
-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.cs60
-rw-r--r--Crypto/src/crypto/agreement/ECDHBasicAgreement.cs50
-rw-r--r--Crypto/src/crypto/agreement/ECDHCBasicAgreement.cs58
-rw-r--r--Crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs64
-rw-r--r--Crypto/src/crypto/agreement/ECMqvBasicAgreement.cs85
-rw-r--r--Crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs64
-rw-r--r--Crypto/src/crypto/agreement/kdf/DHKdfParameters.cs57
-rw-r--r--Crypto/src/crypto/agreement/kdf/DHKekGenerator.cs129
-rw-r--r--Crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs71
-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.cs343
-rw-r--r--Crypto/src/crypto/digests/GeneralDigest.cs118
-rw-r--r--Crypto/src/crypto/digests/LongDigest.cs346
-rw-r--r--Crypto/src/crypto/digests/MD2Digest.cs247
-rw-r--r--Crypto/src/crypto/digests/MD4Digest.cs271
-rw-r--r--Crypto/src/crypto/digests/MD5Digest.cs301
-rw-r--r--Crypto/src/crypto/digests/NullDigest.cs49
-rw-r--r--Crypto/src/crypto/digests/RipeMD128Digest.cs462
-rw-r--r--Crypto/src/crypto/digests/RipeMD160Digest.cs423
-rw-r--r--Crypto/src/crypto/digests/RipeMD256Digest.cs409
-rw-r--r--Crypto/src/crypto/digests/RipeMD320Digest.cs438
-rw-r--r--Crypto/src/crypto/digests/Sha1Digest.cs263
-rw-r--r--Crypto/src/crypto/digests/Sha224Digest.cs268
-rw-r--r--Crypto/src/crypto/digests/Sha256Digest.cs309
-rw-r--r--Crypto/src/crypto/digests/Sha384Digest.cs87
-rw-r--r--Crypto/src/crypto/digests/Sha512Digest.cs90
-rw-r--r--Crypto/src/crypto/digests/ShortenedDigest.cs82
-rw-r--r--Crypto/src/crypto/digests/TigerDigest.cs868
-rw-r--r--Crypto/src/crypto/digests/WhirlpoolDigest.cs397
-rw-r--r--Crypto/src/crypto/encodings/ISO9796d1Encoding.cs273
-rw-r--r--Crypto/src/crypto/encodings/OaepEncoding.cs345
-rw-r--r--Crypto/src/crypto/encodings/Pkcs1Encoding.cs232
-rw-r--r--Crypto/src/crypto/engines/AesEngine.cs525
-rw-r--r--Crypto/src/crypto/engines/AesFastEngine.cs853
-rw-r--r--Crypto/src/crypto/engines/AesLightEngine.cs419
-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/DesEdeEngine.cs100
-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.cs377
-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.cs252
-rw-r--r--Crypto/src/crypto/engines/IdeaEngine.cs341
-rw-r--r--Crypto/src/crypto/engines/IesEngine.cs236
-rw-r--r--Crypto/src/crypto/engines/NaccacheSternEngine.cs432
-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.cs178
-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.cs299
-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/TwofishEngine.cs675
-rw-r--r--Crypto/src/crypto/engines/VMPCEngine.cs139
-rw-r--r--Crypto/src/crypto/engines/VMPCKSA3Engine.cs51
-rw-r--r--Crypto/src/crypto/engines/XTEAEngine.cs168
-rw-r--r--Crypto/src/crypto/generators/BaseKdfBytesGenerator.cs141
-rw-r--r--Crypto/src/crypto/generators/DHBasicKeyPairGenerator.cs38
-rw-r--r--Crypto/src/crypto/generators/DHKeyGeneratorHelper.cs53
-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.cs234
-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.cs61
-rw-r--r--Crypto/src/crypto/generators/DsaParametersGenerator.cs355
-rw-r--r--Crypto/src/crypto/generators/ECKeyPairGenerator.cs174
-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.cs73
-rw-r--r--Crypto/src/crypto/generators/GOST3410ParametersGenerator.cs530
-rw-r--r--Crypto/src/crypto/generators/Kdf1BytesGenerator.cs27
-rw-r--r--Crypto/src/crypto/generators/Kdf2BytesGenerator.cs28
-rw-r--r--Crypto/src/crypto/generators/Mgf1BytesGenerator.cs117
-rw-r--r--Crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs333
-rw-r--r--Crypto/src/crypto/generators/OpenSSLPBEParametersGenerator.cs167
-rw-r--r--Crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs245
-rw-r--r--Crypto/src/crypto/generators/Pkcs5S1ParametersGenerator.cs162
-rw-r--r--Crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs172
-rw-r--r--Crypto/src/crypto/generators/RSABlindingFactorGenerator.cs69
-rw-r--r--Crypto/src/crypto/generators/RsaKeyPairGenerator.cs139
-rw-r--r--Crypto/src/crypto/generators/SCrypt.cs140
-rw-r--r--Crypto/src/crypto/io/CipherStream.cs237
-rw-r--r--Crypto/src/crypto/io/DigestStream.cs140
-rw-r--r--Crypto/src/crypto/io/MacStream.cs139
-rw-r--r--Crypto/src/crypto/io/SignerStream.cs140
-rw-r--r--Crypto/src/crypto/macs/CMac.cs240
-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/GOST28147Mac.cs296
-rw-r--r--Crypto/src/crypto/macs/HMac.cs134
-rw-r--r--Crypto/src/crypto/macs/ISO9797Alg3Mac.cs275
-rw-r--r--Crypto/src/crypto/macs/VMPCMac.cs173
-rw-r--r--Crypto/src/crypto/modes/CbcBlockCipher.cs231
-rw-r--r--Crypto/src/crypto/modes/CcmBlockCipher.cs345
-rw-r--r--Crypto/src/crypto/modes/CfbBlockCipher.cs218
-rw-r--r--Crypto/src/crypto/modes/CtsBlockCipher.cs253
-rw-r--r--Crypto/src/crypto/modes/EAXBlockCipher.cs302
-rw-r--r--Crypto/src/crypto/modes/GCMBlockCipher.cs400
-rw-r--r--Crypto/src/crypto/modes/GOFBBlockCipher.cs223
-rw-r--r--Crypto/src/crypto/modes/IAeadBlockCipher.cs90
-rw-r--r--Crypto/src/crypto/modes/OfbBlockCipher.cs178
-rw-r--r--Crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs337
-rw-r--r--Crypto/src/crypto/modes/SicBlockCipher.cs110
-rw-r--r--Crypto/src/crypto/modes/gcm/BasicGcmExponentiator.cs40
-rw-r--r--Crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs20
-rw-r--r--Crypto/src/crypto/modes/gcm/GcmUtilities.cs149
-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.cs44
-rw-r--r--Crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs64
-rw-r--r--Crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs90
-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.cs53
-rw-r--r--Crypto/src/crypto/parameters/CcmParameters.cs25
-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/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.cs59
-rw-r--r--Crypto/src/crypto/parameters/ECDomainParameters.cs116
-rw-r--r--Crypto/src/crypto/parameters/ECKeyGenerationParameters.cs41
-rw-r--r--Crypto/src/crypto/parameters/ECKeyParameters.cs145
-rw-r--r--Crypto/src/crypto/parameters/ECPrivateKeyParameters.cs87
-rw-r--r--Crypto/src/crypto/parameters/ECPublicKeyParameters.cs86
-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.cs79
-rw-r--r--Crypto/src/crypto/parameters/ParametersWithIV.cs44
-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/prng/CryptoApiRandomGenerator.cs66
-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.cs99
-rw-r--r--Crypto/src/crypto/prng/VMPCRandomGenerator.cs115
-rw-r--r--Crypto/src/crypto/signers/DsaDigestSigner.cs145
-rw-r--r--Crypto/src/crypto/signers/DsaSigner.cs136
-rw-r--r--Crypto/src/crypto/signers/ECDsaSigner.cs156
-rw-r--r--Crypto/src/crypto/signers/ECGOST3410Signer.cs154
-rw-r--r--Crypto/src/crypto/signers/ECNRSigner.cs186
-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/Iso9796d2PssSigner.cs576
-rw-r--r--Crypto/src/crypto/signers/Iso9796d2Signer.cs557
-rw-r--r--Crypto/src/crypto/signers/PssSigner.cs345
-rw-r--r--Crypto/src/crypto/signers/RsaDigestSigner.cs228
-rw-r--r--Crypto/src/crypto/tls/AlertDescription.cs47
-rw-r--r--Crypto/src/crypto/tls/AlertLevel.cs11
-rw-r--r--Crypto/src/crypto/tls/AlwaysValidVerifyer.cs24
-rw-r--r--Crypto/src/crypto/tls/ByteQueue.cs125
-rw-r--r--Crypto/src/crypto/tls/Certificate.cs111
-rw-r--r--Crypto/src/crypto/tls/CertificateRequest.cs28
-rw-r--r--Crypto/src/crypto/tls/CipherSuite.cs136
-rw-r--r--Crypto/src/crypto/tls/ClientCertificateType.cs20
-rw-r--r--Crypto/src/crypto/tls/CombinedHash.cs82
-rw-r--r--Crypto/src/crypto/tls/CompressionMethod.cs20
-rw-r--r--Crypto/src/crypto/tls/ContentType.cs13
-rw-r--r--Crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs67
-rw-r--r--Crypto/src/crypto/tls/DefaultTlsCipherFactory.cs73
-rw-r--r--Crypto/src/crypto/tls/DefaultTlsClient.cs259
-rw-r--r--Crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs76
-rw-r--r--Crypto/src/crypto/tls/DigestAlgorithm.cs21
-rw-r--r--Crypto/src/crypto/tls/ECCurveType.cs29
-rw-r--r--Crypto/src/crypto/tls/ECPointFormat.cs16
-rw-r--r--Crypto/src/crypto/tls/EncryptionAlgorithm.cs32
-rw-r--r--Crypto/src/crypto/tls/ExtensionType.cs31
-rw-r--r--Crypto/src/crypto/tls/HandshakeType.cs19
-rw-r--r--Crypto/src/crypto/tls/ICertificateVerifyer.cs18
-rw-r--r--Crypto/src/crypto/tls/KeyExchangeAlgorithm.cs36
-rw-r--r--Crypto/src/crypto/tls/LegacyTlsAuthentication.cs30
-rw-r--r--Crypto/src/crypto/tls/LegacyTlsClient.cs26
-rw-r--r--Crypto/src/crypto/tls/NamedCurve.cs72
-rw-r--r--Crypto/src/crypto/tls/PskTlsClient.cs182
-rw-r--r--Crypto/src/crypto/tls/RecordStream.cs166
-rw-r--r--Crypto/src/crypto/tls/SecurityParameters.cs26
-rw-r--r--Crypto/src/crypto/tls/SrpTlsClient.cs188
-rw-r--r--Crypto/src/crypto/tls/Ssl3Mac.cs114
-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.cs248
-rw-r--r--Crypto/src/crypto/tls/TlsCipher.cs14
-rw-r--r--Crypto/src/crypto/tls/TlsCipherFactory.cs12
-rw-r--r--Crypto/src/crypto/tls/TlsClient.cs129
-rw-r--r--Crypto/src/crypto/tls/TlsClientContext.cs15
-rw-r--r--Crypto/src/crypto/tls/TlsClientContextImpl.cs37
-rw-r--r--Crypto/src/crypto/tls/TlsCompression.cs12
-rw-r--r--Crypto/src/crypto/tls/TlsCredentials.cs9
-rw-r--r--Crypto/src/crypto/tls/TlsDHKeyExchange.cs201
-rw-r--r--Crypto/src/crypto/tls/TlsDHUtilities.cs70
-rw-r--r--Crypto/src/crypto/tls/TlsDeflateCompression.cs45
-rw-r--r--Crypto/src/crypto/tls/TlsDheKeyExchange.cs56
-rw-r--r--Crypto/src/crypto/tls/TlsDsaSigner.cs51
-rw-r--r--Crypto/src/crypto/tls/TlsDssSigner.cs21
-rw-r--r--Crypto/src/crypto/tls/TlsECDHKeyExchange.cs230
-rw-r--r--Crypto/src/crypto/tls/TlsECDheKeyExchange.cs110
-rw-r--r--Crypto/src/crypto/tls/TlsECDsaSigner.cs21
-rw-r--r--Crypto/src/crypto/tls/TlsException.cs11
-rw-r--r--Crypto/src/crypto/tls/TlsFatalAlert.cs21
-rw-r--r--Crypto/src/crypto/tls/TlsKeyExchange.cs38
-rw-r--r--Crypto/src/crypto/tls/TlsMac.cs106
-rw-r--r--Crypto/src/crypto/tls/TlsNullCipher.cs28
-rw-r--r--Crypto/src/crypto/tls/TlsNullCompression.cs19
-rw-r--r--Crypto/src/crypto/tls/TlsProtocolHandler.cs1259
-rw-r--r--Crypto/src/crypto/tls/TlsPskIdentity.cs15
-rw-r--r--Crypto/src/crypto/tls/TlsPskKeyExchange.cs149
-rw-r--r--Crypto/src/crypto/tls/TlsRsaKeyExchange.cs165
-rw-r--r--Crypto/src/crypto/tls/TlsRsaSigner.cs53
-rw-r--r--Crypto/src/crypto/tls/TlsRsaUtilities.cs42
-rw-r--r--Crypto/src/crypto/tls/TlsSigner.cs18
-rw-r--r--Crypto/src/crypto/tls/TlsSignerCredentials.cs11
-rw-r--r--Crypto/src/crypto/tls/TlsSrpKeyExchange.cs203
-rw-r--r--Crypto/src/crypto/tls/TlsStream.cs89
-rw-r--r--Crypto/src/crypto/tls/TlsUtilities.cs286
-rw-r--r--Crypto/src/crypto/util/Pack.cs219
-rw-r--r--Crypto/src/math/BigInteger.cs3141
-rw-r--r--Crypto/src/math/ec/ECAlgorithms.cs93
-rw-r--r--Crypto/src/math/ec/ECCurve.cs661
-rw-r--r--Crypto/src/math/ec/ECFieldElement.cs1253
-rw-r--r--Crypto/src/math/ec/ECPoint.cs567
-rw-r--r--Crypto/src/math/ec/IntArray.cs485
-rw-r--r--Crypto/src/math/ec/abc/SimpleBigDecimal.cs241
-rw-r--r--Crypto/src/math/ec/abc/Tnaf.cs834
-rw-r--r--Crypto/src/math/ec/abc/ZTauElement.cs36
-rw-r--r--Crypto/src/math/ec/multiplier/ECMultiplier.cs18
-rw-r--r--Crypto/src/math/ec/multiplier/FpNafMultiplier.cs39
-rw-r--r--Crypto/src/math/ec/multiplier/PreCompInfo.cs11
-rw-r--r--Crypto/src/math/ec/multiplier/ReferenceMultiplier.cs30
-rw-r--r--Crypto/src/math/ec/multiplier/WNafMultiplier.cs241
-rw-r--r--Crypto/src/math/ec/multiplier/WNafPreCompInfo.cs46
-rw-r--r--Crypto/src/math/ec/multiplier/WTauNafMultiplier.cs120
-rw-r--r--Crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs41
-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.cs25
-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.cs133
-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.cs203
-rw-r--r--Crypto/src/openpgp/PgpDataValidationException.cs15
-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.cs19
-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.cs15
-rw-r--r--Crypto/src/openpgp/PgpLiteralData.cs63
-rw-r--r--Crypto/src/openpgp/PgpLiteralDataGenerator.cs180
-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.cs200
-rw-r--r--Crypto/src/openpgp/PgpPublicKeyRingBundle.cs280
-rw-r--r--Crypto/src/openpgp/PgpSecretKey.cs666
-rw-r--r--Crypto/src/openpgp/PgpSecretKeyRing.cs301
-rw-r--r--Crypto/src/openpgp/PgpSecretKeyRingBundle.cs281
-rw-r--r--Crypto/src/openpgp/PgpSignature.cs422
-rw-r--r--Crypto/src/openpgp/PgpSignatureGenerator.cs393
-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.cs428
-rw-r--r--Crypto/src/openpgp/PgpV3SignatureGenerator.cs199
-rw-r--r--Crypto/src/openpgp/WrappedGeneratorStream.cs28
-rw-r--r--Crypto/src/openssl/EncryptionException.cs22
-rw-r--r--Crypto/src/openssl/IPasswordFinder.cs9
-rw-r--r--Crypto/src/openssl/MiscPemGenerator.cs277
-rw-r--r--Crypto/src/openssl/PEMException.cs22
-rw-r--r--Crypto/src/openssl/PEMReader.cs407
-rw-r--r--Crypto/src/openssl/PEMUtilities.cs158
-rw-r--r--Crypto/src/openssl/PEMWriter.cs61
-rw-r--r--Crypto/src/openssl/PasswordException.cs22
-rw-r--r--Crypto/src/openssl/Pkcs8Generator.cs111
-rw-r--r--Crypto/src/pkcs/AsymmetricKeyEntry.cs60
-rw-r--r--Crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs75
-rw-r--r--Crypto/src/pkcs/PKCS12StoreBuilder.cs41
-rw-r--r--Crypto/src/pkcs/Pkcs10CertificationRequest.cs466
-rw-r--r--Crypto/src/pkcs/Pkcs10CertificationRequestDelaySigned.cs150
-rw-r--r--Crypto/src/pkcs/Pkcs12Entry.cs64
-rw-r--r--Crypto/src/pkcs/Pkcs12Store.cs1231
-rw-r--r--Crypto/src/pkcs/Pkcs12Utilities.cs77
-rw-r--r--Crypto/src/pkcs/PrivateKeyInfoFactory.cs214
-rw-r--r--Crypto/src/pkcs/X509CertificateEntry.cs60
-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.cs460
-rw-r--r--Crypto/src/pkix/PkixCertPathBuilder.cs205
-rw-r--r--Crypto/src/pkix/PkixCertPathBuilderException.cs19
-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.cs218
-rw-r--r--Crypto/src/pkix/PkixCertPathValidatorResult.cs69
-rw-r--r--Crypto/src/pkix/PkixCertPathValidatorUtilities.cs1194
-rw-r--r--Crypto/src/pkix/PkixCrlUtilities.cs114
-rw-r--r--Crypto/src/pkix/PkixNameConstraintValidator.cs1937
-rw-r--r--Crypto/src/pkix/PkixNameConstraintValidatorException.cs12
-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.cs2448
-rw-r--r--Crypto/src/pkix/Rfc3281CertPathUtilities.cs608
-rw-r--r--Crypto/src/pkix/TrustAnchor.cs259
-rw-r--r--Crypto/src/security/AgreementUtilities.cs106
-rw-r--r--Crypto/src/security/CipherUtilities.cs696
-rw-r--r--Crypto/src/security/DigestUtilities.cs189
-rw-r--r--Crypto/src/security/DotNetUtilities.cs222
-rw-r--r--Crypto/src/security/GeneralSecurityException.cs26
-rw-r--r--Crypto/src/security/GeneratorUtilities.cs341
-rw-r--r--Crypto/src/security/InvalidKeyException.cs11
-rw-r--r--Crypto/src/security/InvalidParameterException.cs11
-rw-r--r--Crypto/src/security/KeyException.cs11
-rw-r--r--Crypto/src/security/MacUtilities.cs239
-rw-r--r--Crypto/src/security/NoSuchAlgorithmException.cs12
-rw-r--r--Crypto/src/security/ParameterUtilities.cs327
-rw-r--r--Crypto/src/security/PbeUtilities.cs658
-rw-r--r--Crypto/src/security/PrivateKeyFactory.cs221
-rw-r--r--Crypto/src/security/PublicKeyFactory.cs253
-rw-r--r--Crypto/src/security/SecureRandom.cs228
-rw-r--r--Crypto/src/security/SecurityUtilityException.cs33
-rw-r--r--Crypto/src/security/SignatureException.cs11
-rw-r--r--Crypto/src/security/SignerUtilities.cs550
-rw-r--r--Crypto/src/security/WrapperUtilities.cs153
-rw-r--r--Crypto/src/security/cert/CertificateEncodingException.cs11
-rw-r--r--Crypto/src/security/cert/CertificateException.cs11
-rw-r--r--Crypto/src/security/cert/CertificateExpiredException.cs11
-rw-r--r--Crypto/src/security/cert/CertificateNotYetValidException.cs11
-rw-r--r--Crypto/src/security/cert/CertificateParsingException.cs11
-rw-r--r--Crypto/src/security/cert/CrlException.cs11
-rw-r--r--Crypto/src/tsp/GenTimeAccuracy.cs33
-rw-r--r--Crypto/src/tsp/TSPAlgorithms.cs48
-rw-r--r--Crypto/src/tsp/TSPException.cs25
-rw-r--r--Crypto/src/tsp/TSPUtil.cs202
-rw-r--r--Crypto/src/tsp/TSPValidationException.cs39
-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.cs226
-rw-r--r--Crypto/src/util/BigIntegers.cs72
-rw-r--r--Crypto/src/util/Enums.cs72
-rw-r--r--Crypto/src/util/Platform.cs171
-rw-r--r--Crypto/src/util/Strings.cs107
-rw-r--r--Crypto/src/util/collections/CollectionUtilities.cs71
-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.cs95
-rw-r--r--Crypto/src/util/encoders/Base64Encoder.cs307
-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.cs131
-rw-r--r--Crypto/src/util/encoders/HexEncoder.cs164
-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.cs54
-rw-r--r--Crypto/src/util/io/BaseOutputStream.cs54
-rw-r--r--Crypto/src/util/io/PushbackStream.cs52
-rw-r--r--Crypto/src/util/io/StreamOverflowException.cs27
-rw-r--r--Crypto/src/util/io/Streams.cs94
-rw-r--r--Crypto/src/util/io/TeeInputStream.cs54
-rw-r--r--Crypto/src/util/io/TeeOutputStream.cs42
-rw-r--r--Crypto/src/util/io/pem/PemGenerationException.cs26
-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.cs155
-rw-r--r--Crypto/src/util/zlib/ZInflaterInputStream.cs131
-rw-r--r--Crypto/src/util/zlib/ZInputStream.cs196
-rw-r--r--Crypto/src/util/zlib/ZOutputStream.cs220
-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.cs187
-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.cs188
-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.cs15
-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.cs25
-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.cs25
-rw-r--r--Crypto/src/x509/store/X509StoreFactory.cs61
-rw-r--r--License.html39
-rw-r--r--Portable.BouncyCastle.nuspec41
-rw-r--r--pack.cmd1
1138 files changed, 203775 insertions, 0 deletions
diff --git a/.nuget/NuGet.Config b/.nuget/NuGet.Config
new file mode 100644
index 000000000..67f8ea046
--- /dev/null
+++ b/.nuget/NuGet.Config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <solution>
+    <add key="disableSourceControlIntegration" value="true" />
+  </solution>
+</configuration>
\ No newline at end of file
diff --git a/.nuget/NuGet.exe b/.nuget/NuGet.exe
new file mode 100644
index 000000000..9cba6edbf
--- /dev/null
+++ b/.nuget/NuGet.exe
Binary files differdiff --git a/BouncyCastle-PCL.sln b/BouncyCastle-PCL.sln
new file mode 100644
index 000000000..624b845fe
--- /dev/null
+++ b/BouncyCastle-PCL.sln
@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{43196EF9-B75F-4ABB-8967-DAFD621A7D05}"
+	ProjectSection(SolutionItems) = preProject
+		Portable.BouncyCastle.nuspec = Portable.BouncyCastle.nuspec
+		README.md = README.md
+	EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "crypto", "Crypto\crypto.csproj", "{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{38872A5F-E87E-4FAD-B109-8EB7B2E6A4A0}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/Crypto/Contributors.html b/Crypto/Contributors.html
new file mode 100644
index 000000000..b37af312f
--- /dev/null
+++ b/Crypto/Contributors.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+	<head>
+		<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
+		<title>Contributors</title>
+	</head>
+	<body>
+		<h2>The Bouncy Castle Cryptographic C#&reg; API</h2>
+		<h3>Contributors:</h3>
+		<p>The following people have contributed to the C# Bouncy Castle Cryptography 
+			Package.</p>
+		<p>Thanks, may your castles never deflate!</p>
+		<ul>
+			<li>
+				<p>Kaiser Yang &lt;kaiseryang&#064yahoo.com&gt; - initial port of the lightweight 
+					API and ASN.1 library. Finding BigInteger loop problem.</p>
+			</li>
+			<li>
+				<p>Asier Murciego &lt;a.murciego&#064captiva-sys.es&gt; - Further patching to 
+					BigInteger library.</p>
+			</li>
+			<li>
+				<p>Megan Woods &lt;megan.woods&#064widestreet.com.au&gt; - X509 certificate 
+					generation, RSA/DSA digest signature classes.</p>
+			</li>
+			<li>
+				<p>David Del Vecchio &lt;ddelvecc&#064virginia.edu&gt; - patches to RSA Pkcs1 
+					Signature generation OID issues, help with clarifications on DateTime and 
+					certificates.</p>
+			</li>
+			<li>
+				<p>Nelson Fernandez &lt;nelson-bc&#064kpanic.com.ar&gt; - patches to allow 
+					compilation under mono.</p>
+			</li>
+			<li>
+				<p>Paulo Soares &lt;psoares&#064consiste.pt&gt; - patches to X509CertificateParser, 
+					C# port of JZlib plus inflater/deflater streams, C# port of Apache BZip2 
+					classes.</p>
+			</li>
+			<li>
+				<p>Pawel Niewiadomski &lt;11110000b&#064gmail.com&gt; - patches for X509 and CMS, 
+					unit test for time classes.</p>
+			</li>
+			<li>
+				<p>Jesper Johansen &lt;jesper&#064hc.jay.net&gt; - bug fix for DerT61String 
+					encodings.</p>
+			</li>
+			<li>
+				<p>Adam Sternberg &lt;agsternberg&#064gmail.com&gt; - identified problem with 
+					generation of PGP public keyrings.</p>
+			</li>
+			<li>
+				<p>Kirill Zhuklinets &lt;zhuklinets_k&#064gaz-is.ru&gt; - initial submission of 
+					bulk of Asn1.Esf classes (RFC 3126).</p>
+			</li>
+			<li>
+				<p>Dr Andrew Gray &lt;andrew.gray&#064rcrt.co.uk&gt; - identified problem with 
+					BigInteger.ModPow for negative exponents.</p>
+			</li>
+			<li>
+				<p>Mauricio Ulate &lt;mulate&#064gmail.com&gt; - identified problem with non-ASCII 
+					pass phrases in PGP.</p>
+			</li>
+			<li>
+				<p>John Allberg &lt;John.Allberg&#064teliasonera.com&gt; - initial implementation 
+					of CryptoApiRandomGenerator.</p>
+			</li>
+			<li>
+				<p>Mattias &Ouml;hrn &lt;mattias.ohrn&#064gmail.com&gt; - identified problem with 
+					Pkcs12Store.Save and provided fix.</p>
+			</li>
+			<li>
+				<p>Jen Andre &lt;jandre&#064gmail.com&gt; - initial implementation of 
+					case-insensitive searches for PGP keyrings.</p>
+			</li>
+			<li>
+				<p>#Cyrille37# &lt;cyrille37&#064gmail.com&gt; - identified problem with 
+					BigInteger.ModInverse for negative values.</p>
+			</li>
+			<li>
+				<p>David Reis Jr &lt;davidreis&#064yahoo.com&gt; - bug fix for X509CrlStoreSelector 
+					handling of NextUpdate, fix handling of null parameters for DSA in key 
+					factories, initial port of Pkix namespace and supporting tests.
+				</p>
+			</li>
+			<li>
+				<p>Ivan Peev &lt;ivan.peev&#064cozyroc.com&gt; - bug fix for version string 
+					displayed in PGP armored output.</p>
+			</li>
+			<li>
+				<p>Hector Ornelas Aciga &lt;hector.ornelas&#064sat.gob.mx&gt; - patch to add support for PKCS#5 Scheme 2 keys.</p>
+			</li>
+			<li>
+				<p>Tom Van Holle &lt;tvh&#064dsoft.be&gt; - patch to add new class: Pkcs10CertificationRequestDelaySigned.</p>
+			</li>
+			<li>
+				<p>Kalev Lember &lt;kalev&#064smartlink.ee&gt; - patch to fix compilation problem under Mono 2.8+.</p>
+			</li>
+			<li>
+				<p>Kyle Hamilton &lt;kyanha.bouncycastle&#064kyanha.net&gt; - identified problem with BigInteger.Multiply, patch for MiscPemGenerator infinite recursion.</p>
+			</li>
+			<li>
+				<p>Atanas Krachev &lt;akrachev&#064gmail.com&gt; - added support for revocation signatures in OpenPGP.</p>
+			</li>
+			<li>
+				<p>Torsten Moschny &lt;t.moschny&#064web.de&gt; - identified problem where PrivateKeyFactory/PublicKeyFactory failed to preserve publicKeyParamSet for EC keys.</p>
+			</li>
+			<li>
+				<p>Thomas Heggelund &lt;the&#064dips.no&gt; - identified problem with RSAParameters fields requiring zero-byte padding to satisfy .NET.</p>
+			</li>
+			<li>
+				<p>Laszlo Magyar &lt;lmagyar1973&#064gmail.com&gt; - patch to fix problem with SubjectDirectoryAttributes constructor.</p>
+			</li>
+		</ul>
+	</body>
+</html>
diff --git a/Crypto/License.html b/Crypto/License.html
new file mode 100644
index 000000000..0dae3a978
--- /dev/null
+++ b/Crypto/License.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+  <title>License</title>
+</head>
+<body>
+<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
+(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
+Software without restriction, including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sub license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:<br>
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.<br>
+<span style="font-weight: bold;">THE SOFTWARE IS PROVIDED "AS IS",
+WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">INCLUDING BUT NOT LIMITED TO THE
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">PURPOSE AND NONINFRINGEMENT. IN NO
+EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">DEALINGS IN THE SOFTWARE.<br>
+<br>
+</span>
+</body>
+</html>
diff --git a/Crypto/Readme.html b/Crypto/Readme.html
new file mode 100644
index 000000000..afa75e882
--- /dev/null
+++ b/Crypto/Readme.html
@@ -0,0 +1,455 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+	<head>
+		<title>Notes</title>
+		<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">
+	</head>
+	<body>
+		<h2><a class="mozTocH2" name="mozTocId533031"></a>The Bouncy Castle Cryptographic 
+			C# API</h2>
+		<h3><a class="mozTocH3" name="mozTocId685176"></a>Contents:<br>
+		</h3>
+		<ol id="mozToc">
+			<!--mozToc h1 1 h2 2 h3 3 h4 4 h5 5 h6 6--><li><a href="#mozTocId533031">The Bouncy 
+					Castle Cryptographic C# API</a>
+		<ol>
+			<li>
+		<ol>
+			<li>
+				<a href="#mozTocId685176">Contents: </a>
+			<li>
+				<a href="#mozTocId66345">License &amp; Contributors:</a>
+			<li>
+				<a href="#mozTocId575388">Features:</a>
+			<li>
+				<a href="#mozTocId211208">How To Build.</a>
+			<li>
+				<a href="#mozTocId245743">The Source:</a>
+			<li>
+				<a href="#mozTocId326820">Documentation:</a>
+			<li>
+				<a href="#mozTocId358608">For first time users.</a>
+			<li>
+				<a href="#mozTocId3413">Notes:</a>
+		<ol>
+			<li>
+				<a href="#mozTocId85313">Release 1.7</a>
+			<li>
+				<a href="#mozTocId85312">Release 1.6.1</a>
+			<li>
+				<a href="#mozTocId85311">Release 1.6</a>
+			<li>
+				<a href="#mozTocId85310">Release 1.5</a>
+			<li>
+				<a href="#mozTocId85309">Release 1.4</a>
+			<li>
+				<a href="#mozTocId85308">Release 1.3</a>
+			<li>
+				<a href="#mozTocId85307">Release 1.2</a>
+			<li>
+				<a href="#mozTocId85306">Release 1.1</a>
+			<li>
+				<a href="#mozTocId85305">Release 1.0</a>
+			<li>
+				<a href="#mozTocId85304">Tuesday Febuary 1, 2005</a>
+			<li>
+				<a href="#mozTocId498363">Sunday December 12, 2004</a></li>
+		</ol>
+		<li>
+			<a href="#mozTocId948186">Trademarks. </a>
+		</li>
+		</ol> </li> </ol> </li> </ol>
+		<br>
+		<hr style="WIDTH: 100%; HEIGHT: 2px">
+		<h3><a class="mozTocH3" name="mozTocId66345"></a>License &amp; Contributors:</h3>
+		See <a href="License.html">License</a> &amp; <a href="Contributors.html">Contributors</a>
+		files.<br>
+		&nbsp;<br>
+		<hr style="WIDTH: 100%; HEIGHT: 2px">
+		<br>
+		<h3><a class="mozTocH3" name="mozTocId575388"></a>Features:</h3>
+		<ul>
+			<li>
+			Generation and parsing of PKCS-12 files.
+			<li>
+			X.509: Generators and parsers for V1 and V3 certificates, V2 CRLs and attribute 
+			certificates.
+			<li>
+			PBE algorithms supported by PBEUtil: PBEwithMD2andDES-CBC, 
+			PBEwithMD2andRC2-CBC, PBEwithMD5andDES-CBC, PBEwithMD5andRC2-CBC, 
+			PBEwithSHA1andDES-CBC, PBEwithSHA1andRC2-CBC, PBEwithSHA-1and128bitRC4, 
+			PBEwithSHA-1and40bitRC4, PBEwithSHA-1and3-keyDESEDE-CBC, 
+			PBEwithSHA-1and2-keyDESEDE-CBC, PBEwithSHA-1and128bitRC2-CBC, 
+			PBEwithSHA-1and40bitRC2-CBC, PBEwithHmacSHA-1, PBEwithHmacSHA-224, 
+			PBEwithHmacSHA-256, PBEwithHmacRIPEMD128, PBEwithHmacRIPEMD160, and 
+			PBEwithHmacRIPEMD256.
+			<li>
+			Signature algorithms supported by SignerUtilities: MD2withRSA, MD4withRSA, 
+			MD5withRSA, RIPEMD128withRSA, RIPEMD160withECDSA, RIPEMD160withRSA, 
+			RIPEMD256withRSA, SHA-1withRSA, SHA-224withRSA, SHA-256withRSAandMGF1, 
+			SHA-384withRSAandMGF1, SHA-512withRSAandMGF1, SHA-1withDSA, and SHA-1withECDSA.
+			<li>
+			Symmetric key algorithms: AES, Blowfish, Camellia, CAST5, CAST6, DESede, DES, 
+			GOST28147, HC-128, HC-256, IDEA, ISAAC, NaccacheStern, Noekeon, RC2, RC4, 
+			RC5-32, RC5-64, RC6, Rijndael, Salsa20, SEED, Serpent, Skipjack, TEA/XTEA,
+			Twofish and VMPC.
+			<li>
+			Symmetric key modes: CBC, CFB, CTS, GOFB, OFB, OpenPGPCFB, and SIC (or CTR).
+			<li>
+			Symmetric key paddings: ISO10126d2, ISO7816d4, PKCS-5/7, TBC, X.923, and Zero 
+			Byte.
+			<li>
+			Asymmetric key algorithms: RSA (with blinding), ElGamal, DSA, and ECDSA.
+			<li>
+			Asymmetric key paddings/encodings: ISO9796d1, OAEP, and PKCS-1.
+			<li>
+			AEAD block cipher modes: CCM, EAX, and GCM.
+			<li>
+			Digests: GOST3411, MD2, MD4, MD5, RIPEMD128, RIPEMD160, RIPEMD256, RIPEMD320, 
+			SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, Tiger, and Whirlpool.
+			<li>
+			Signer mechanisms: DSA, ECDSA, ECGOST3410, GOST3410, ISO9796d2, PSS, RSA.
+			<li>
+			Key Agreement: Diffie-Hellman, EC-DH, SRP-6a.
+			<li>
+			Macs: CBCBlockCipher, CFBBlockCipher, GOST28147, HMac, ISO9797 Alg. 3, and VMPCMAC.
+			<li>
+			PBE generators: PKCS-12, and PKCS-5 - schemes 1 and 2.
+			<li>
+			OpenPGP (RFC 2440)
+			<li>
+			Cryptographic Message Syntax (CMS, RFC 3852), including streaming API.
+			<li>
+			Online Certificate Status Protocol (OCSP, RFC 2560).
+			<li>
+			Time Stamp Protocol (TSP, RFC 3161).
+			<li>
+			Elliptic Curve Cryptography (support for F2m and Fp curves).
+			<li>
+				Reading/writing of PEM files, including RSA and DSA keys, with a variety of 
+				encryptions.
+			</li>
+			<li>PKIX certificate path validation</li>
+		</ul>
+		<br>
+		<p><b>Porting notes from the old ASN.1 library</b> For the most part code using the 
+			old subset of ASN.1 classes should be easy to transfer, providing the following 
+			changes are made:
+		</p>
+		<ul>
+			<li>
+			DERObject becomes Asn1Object
+			<li>
+			DEREncodable becomes Asn1Encodable
+			<li>
+			GetDERObject() becomes ToAsn1Object()
+			<li>
+			BERConstructedOctetString becomes BerOctetString
+			<li>
+			If you were using the older mutable DERConstructedSequence/Set and 
+			BERConstructedSequence, use an Asn1EncodableVector in conjunction with 
+			DerSequence/Set and BerSequence
+			<li>
+			BERInputStream and DERInputStream are replaced with Asn1InputStream
+			<li>
+				AsymmetricKeyParameter is now in the Org.Bouncycastle.Crypto namespace</li>
+		</ul>
+		<br>
+		<hr style="WIDTH: 100%; HEIGHT: 2px">
+		<h3><a class="mozTocH3" name="mozTocId211208"></a>How To Build.</h3>
+		<p>
+			The BC C# API uses NAnt (<a href="http://nant.sourceforge.net/">http://nant.sourceforge.net</a>) 
+			to provide a platform independent build environment (suggested version NAnt 0.90).
+			There is also a solution file for Visual Studio, and for MonoDevelop. The API works
+			with .NET Framework 1.1 and above. It has been successfully built and tested with Mono
+			versions from 1.1.13 onwards. The source code can be built for .NET Compact Framework 1.0
+			by setting the compilation flag NETCF_1_0, or .NET Compact Framework 2.0 by setting NETCF_2_0,
+			or Silverlight 2 by setting SILVERLIGHT.
+		</p>
+		Using a command prompt (DOS window), cd into the 'crypto' folder of this 
+		distribution.<br>
+		<br>
+		<span style="FONT-WEIGHT: bold">Use,</span><br>
+		<ul>
+			<li>
+				'<span style="FONT-WEIGHT: bold">nant</span>' without arguments to compile 
+			debug code, the tests and run the tests.
+			<li>
+				'<span style="FONT-WEIGHT: bold">nant compile-release</span>' to compile 
+			release code.
+			<li>
+				'<span style="FONT-WEIGHT: bold">nant compile-debug</span>' to compile 
+			debug code.
+			<LI>
+				'<SPAN style="FONT-WEIGHT: bold">nant test</SPAN>' to run the included unit 
+				tests (using NUnit; you may need to edit the build file to set the location 
+				where NUnit is installed).</LI>
+		</ul>
+		<P>
+			<span style="FONT-WEIGHT: bold">Output:</span><br>
+			<br>
+			&nbsp;&nbsp;&nbsp; The compiled API can be found in the 'api/bin/release' &amp; 
+			'api/bin/debug' directories.<br>
+			&nbsp;&nbsp;&nbsp; The compiled tests can be found in the 'test/bin' directory 
+			(by default a debug build is used for testing).<br>
+		<P>
+			<hr style="WIDTH: 100%; HEIGHT: 2px">
+		<P></P>
+		<h3><a class="mozTocH3" name="mozTocId245743"></a><span style="FONT-WEIGHT: bold">The Source:</span></h3>
+		Source code can be found in the 'src'directory.<br>
+		<br>
+		<hr style="WIDTH: 100%; HEIGHT: 2px">
+		<h3><a class="mozTocH3" name="mozTocId326820"></a><span style="FONT-WEIGHT: bold"></span>Documentation:</h3>
+		<P>There is limited documentation available at the moment. Some of the source 
+			contains XML comments, but this is a work in progress. We will be working to 
+			improve this now that 1.0 is out the door.</P>
+		<P>
+			<hr style="WIDTH: 100%; HEIGHT: 2px">
+		<P></P>
+		<h3><a class="mozTocH3" name="mozTocId358608"></a>For first time users.</h3>
+		&nbsp;<span style="FONT-WEIGHT: bold">Java heritage,</span><br>
+		<br>
+		The Bouncy Castle C# API is a port of the Bouncy Castle Java APIs. 
+		Approximately %80 of the functionality in the Java build has now been ported. 
+		For the most part, the naming conventions of the .NET platform have been 
+		adopted. The C# API is constantly kept uptodate with bug fixes and new test 
+		cases from the Java build (and vice versa sometimes), thus benefitting from the 
+		large user base and real-world use the Java version has seen.<br>
+		<br>
+		<span style="FONT-WEIGHT: bold">Please consider.</span><br>
+		<br>
+		The Bouncy Castle C# API is a library of transformations that when combined 
+		properly will enable developers to create standard conforming cryptographic 
+		systems. In order to use this API you must have some knowledge of how to build 
+		cryptographic systems, namely what transformations to use and the when, where 
+		and why of their use.<br>
+		Developing good cryptographic systems takes practice and understanding.<br>
+		<br>
+		There are many resources available online and in book shops; please use those 
+		to your advantage.<br>
+		<br>
+		<hr style="WIDTH: 100%; HEIGHT: 2px">
+		<h3><a class="mozTocH3" name="mozTocId3413"></a>Notes:</h3>
+		<H4><A class="mozTocH4" name="mozTocId85313"></A>Release 1.7, Thursday April 7, 2011</H4>
+<h5>Additional Features and Functionality</h5>
+<ul>
+<li>TLS now supports client authentication.</li>
+<li>TLS now supports compression.</li>
+<li>TLS now supports ECC cipher suites (RFC 4492).</li>
+<li>Library can now be built for Silverlight (2.0 and above).</li>
+<li>ASN.1 classes for CRMF (RFC 4211) and CMP (RFC 4210) have been added.</li>
+<li>Further performance improvements to GCM mode.</li>
+<li>BufferedBlockCipher will now always reset after a DoFinal().</li>
+<li>An IV can now be passed to an Iso9797Alg3Mac</li>
+</ul>
+<h5>Additional Notes</h5>
+<ul>
+<li>See list of resolved issues at
+<a href="http://www.bouncycastle.org/jira/secure/IssueNavigator.jspa?reset=true&&pid=10001&fixfor=10110&sorter/field=issuekey&sorter/order=DESC">
+Bouncy Castle JIRA C# 1.7</a></li>
+</ul>
+		<H4><A class="mozTocH4" name="mozTocId85312"></A>Release 1.6.1, Monday February 8, 2010</H4>
+<ul>
+<li>A point release to rectify some problems with the released assembly of 1.6 version.</li>
+</ul>
+		<H4><A class="mozTocH4" name="mozTocId85311"></A>Release 1.6, Thursday February 4, 2010</H4>
+<h5>Defects Fixed</h5>
+<ul>
+<li>X509DefaultEntryConverter was not recognising telephone number as a PrintableString field. This has been fixed.</li>
+<li>OpenPGP now supports UTF-8 in file names for literal data.</li>
+</ul>
+<h5>Security Advisory</h5>
+<ul>
+<li>This version has been specifically reviewed to eliminate possible timing attacks on algorithms such as GCM and CCM mode.</li>
+</ul>
+<h5>Additional Features and Functionality</h5>
+<ul>
+<li>Support for PSS signatures has been added to CMS.</li>
+<li>SubjectKeyIdentifier now supports both methods specified in RFC 3280, section 4.2.1.2 for generating the identifier.</li>
+<li>Performance of GCM mode has been greatly improved (on average 10x).</li>
+<li>Support for mac lengths of 96, 104, 112, and 120 bits has been added to existing support for 128 bits in GCMBlockCipher.</li>
+<li>Support for raw signatures has been extended to RSA, RSA-PSS and ECDSA. RSA support can be used in CmsSignedDataStreamGenerator to support signatures without signed attributes.</li>
+<li>Support for EC MQV has been added to the light weight API and the CMS library.</li>
+</ul>
+<h5>Additional Notes</h5>
+<ul>
+<li>See list of resolved issues at
+<a href="http://www.bouncycastle.org/jira/secure/IssueNavigator.jspa?reset=true&&pid=10001&fixfor=10100&sorter/field=issuekey&sorter/order=DESC">
+Bouncy Castle JIRA C# 1.6</a></li>
+</ul>
+		<H4><A class="mozTocH4" name="mozTocId85310"></A>Release 1.5, Tuesday August 18, 2009</H4>
+<h5>Defects Fixed</h5>
+<ul>
+<li>Correct the ASN.1 class for AuthorityInformationAccess.</li>
+<li>In the Bcpg libs, armored output now inserts the correct version string.</li>
+<li>EssCertIDv2 encoding now complies with RFC 5035.</li>
+<li>ECDSA now computes correct signatures for oversized hashes when the order of the base point is not a multiple of 8 in compliance with X9.62-2005.</li>
+<li>Standard name "DiffieHellman" is now supported in factory classes.</li>
+<li>Better support for equality tests for '#' encoded entries has been added to X509Name.</li>
+<li>'=' inside a X509Name was not being properly escaped. This has been fixed.</li>
+<li>ApplicationSpecific ASN.1 tags are now recognised in BER data. The GetObject() method now handles processing of arbitrary tags.</li>
+<li>Multiplication by negative powers of two is fixed in BigInteger.</li>
+<li>Multiple countersignature attributes are now correctly collected.</li>
+<li>Two bugs in HC-128 and HC-256 related to sign extension and byte swapping have been fixed. The implementations now pass the latest ecrypt vector tests.</li>
+</ul>
+<h5>Security Advisory</h5>
+<ul>
+<li>The effect of the sign extension bug was to decrease the key space the HC-128 and HC-256 ciphers were operating in and the byte swapping inverted every 32 bits of the generated stream. If you are using either HC-128 or HC-256 you must upgrade to this release.</li>
+</ul>
+<h5>Additional Features and Functionality</h5>
+<ul>
+<li>PKIX certificate path validation</li>
+<li>Accept duplicate PKCS#9 FriendlyName attributes in PKCS#12 keystore.</li>
+<li>Add support for PKCS#5 Scheme 2 keys.</li>
+<li>Camellia performance improved.</li>
+<li>A smaller version of Camellia, CamelliaLightEngine has also been added.</li>
+<li>CmsSignedData generation now supports SubjectKeyIdentifier as well as use of issuer/serial.</li>
+<li>A CMS PBE key holder for UTF8 keys has been added to the CMS API.</li>
+<li>Salt and iteration count can now be recovered from PasswordRecipientInformation.</li>
+<li>Support for reading and extracting personalised certificates in PGP Secret Key rings has been added.</li>
+<li>Support for EAC algorithms has been added to CMS.</li>
+<li>Asn1Dump now supports a verbose mode for displaying the contents of octet and bit strings.</li>
+<li>Support for the SRP-6a protocol has been added.</li>
+</ul>
+<h5>Additional Notes</h5>
+<ul>
+<li>See also the list of resolved issues at
+<a href="http://www.bouncycastle.org/jira/secure/IssueNavigator.jspa?reset=true&&pid=10001&fixfor=10080&sorter/field=issuekey&sorter/order=DESC">
+Bouncy Castle JIRA C# 1.5</a></li>
+</ul>
+		<H4><A class="mozTocH4" name="mozTocId85309"></A>Release 1.4, Thursday August 8, 2008</H4>
+<h5>Defects Fixed</h5>
+<ul>
+<li>The GeneralName string constructor now supports IPv4 and IPv6 address parsing.</li>
+<li>EAX mode was not handling non-zero offsetted data correctly and failing. This has been fixed.</li>
+<li>EAX mode ciphers were not resetting correctly after a DoFinal/Reset. This has been fixed.</li>
+<li>Some boolean parameters to IssuingDistributionPoint were being reversed. This has been fixed.</li><li>A zero length RDN would cause an exception in an X509Name. This has been fixed.</li>
+<li>Specifying a greater than 32bit length for a stream and relying on the default BcpgOutputStream resulted in corrupted data. This has been fixed.</li>
+<li>Pkcs7Padding validation would not fail if pad length was 0. This has been fixed.</li>
+<li>Signature creation time was not being properly initialised in new V4 PGP signature objects although the encoding was correct. This has been fixed.</li>
+<li>The '+' character can now be escaped or quoted in the constructor for X509Name.</li>
+<li>IV handling in CMS for SEED and Camellia was incorrect. This has been fixed.</li>
+<li>ASN.1 stream parser now throws exceptions for unterminated sequences.</li>
+<li>X509CertificateParser/X509CrlParser now handle multiple certificates/CRLs in streams that don't support seeking.</li>
+<li>The CertID class used by the TSP library was incomplete. This has been fixed</li>
+<li>\# is now properly recognised in the X509Name class.</li>
+<li>BigInteger.ModInverse was failing for negative values. This has been fixed.</li>
+<li>CMS API now supports RSASSA-PSS signatures with explicit salt length.</li>
+</ul>
+<h5>Additional Features and Functionality</h5>
+<ul>
+<li>ASN.1 libs now support high tag numbers.</li>
+<li>Galois/Counter Mode (GCM) has been added.</li>
+<li>The TSP API now supports parsing and validation of responses with V2 signing certificate entries.</li>
+<li>Unnecessary local ID attributes on certificates in PKCS12 files are now automatically removed.</li>
+<li>New Pkcs12StoreBuilder class supports generation of PKCS12 files with both certificates and keys protected by 3DES.</li>
+<li>Certifications associated with user attributes can now be created, verified and removed in OpenPGP.</li>
+<li>API support now exists for CMS countersignature reading and production.</li>
+<li>A new class LazyAsn1InputStream supports lazy evaluation of DER sequences and sets, considerably reducing memory requirements in some scenarios.</li>
+<li>KeyPurposeId class has been updated for RFC 4945.</li>
+<li>Initial support has been added for HP_CERTIFICATE_REQUEST in the TLS API.</li>
+<li>PGP example programs now handle blank names in literal data objects.</li>
+<li>The ProofOfPossession class now better supports the underlying ASN.1 structure.</li>
+</ul>
+<h5>Additional Notes</h5>
+<ul>
+<li>Due to problems for some users caused by the presence of the IDEA algorithm, an implementation is no
+longer included in the default assembly. Only the assembly named BouncyCastle.CryptoExt now includes IDEA.</li>
+<li>See also the list of resolved issues at
+<a href="http://www.bouncycastle.org/jira/secure/IssueNavigator.jspa?reset=true&&pid=10001&fixfor=10050&sorter/field=issuekey&sorter/order=DESC">
+Bouncy Castle JIRA C# 1.4</a></li>
+</ul>
+		<H4><A class="mozTocH4" name="mozTocId85308"></A>Release 1.3, Saturday December 8, 2007</H4>
+		<P>
+			ASN.1 stream parsing now handles definite length encodings efficiently.<br>
+			Buffering in the streaming CMS has been reworked. Throughput is now usually higher and the behaviour is more predictable.<br>
+			BcpgInputStream now handles data blocks in the 2**31-&gt;2**32-1 range.<br>
+			Some confusion over the parameters J and L in connection with Diffie-Hellman has been resolved.<br>
+			Added CryptoApiRandomGenerator, a wrapper for RNGCryptoServiceProvider.<br>
+			Added VMPC stream cipher, VMPCMAC and a VMPC-based implementation of IRandomGenerator.<br>
+			Added support in OpenPGP for fetching keyrings by case-insensitive user ID [#BMA-8].<br>
+			Fixed a vulnerability of CMS signatures that do not use signed attributes (Bleichenbacher RSA forgery).<br>
+			Fixed a bug causing second and later encrypted objects to be ignored in KeyBasedFileProcessor example.<br>
+			Fixed case-sensitivity issue with deletion from a PKCS#12 file.<br>
+			Fixed problem overwriting entities in a PKCS#12 file.<br>
+			Fixed PgpUtilities.MakeKeyFromPassPhrase for 8-bit characters [#BMA-13].<br>
+			Fixed duplicate certificate problem in Pkcs12Store.Save [#BMA-12].<br>
+			Fixed NAnt build under Mono [#BMA-10].<br>
+			Fixed BigInteger.ModPow for negative exponents [#BMA-7].<br>
+		</P>
+		<H4><A class="mozTocH4" name="mozTocId85307"></A>Release 1.2, Thursday July 5, 2007</H4>
+		<P>
+			Source now builds on .NET Compact Framework 1.0 (compilation flag NETCF_1_0).<br>
+			Release assembly now signed with a strong name.<br>
+			Added CCM and EAX block cipher modes.<br>
+			Added Noekeon block cipher.<br>
+			Added HC-128, HC-256, and ISAAC stream ciphers.<br>
+			Added RIPEMD160withECDSA signature algorithm.<br>
+			Added support for notation data signature subpackets to OpenPGP.<br>
+			Added support for parsing of experimental signatures to OpenPGP.<br>
+			Added the complete set of SEC-2 EC curves.<br>
+			Added support for implicit tagging to DerApplicationSpecific.<br>
+			Added remaining ASN.1 structures from RFC 3126 to Asn1.Esf namespace.<br>
+			Performance of ECDSA improved.<br>
+			Performance of ASN.1 stream parsing improved.<br>
+			Fixed default private key length for Diffie-Hellman parameters.<br>
+			Fixed DerT61String to correctly support 8-bit characters.<br>
+			Fixed duplicate attribute problem in Pkcs12Store.Save.<br>
+			Fixed a problem writing public keys in OpenPGP [#BMA-5].<br>
+		</P>
+		<H4><A class="mozTocH4" name="mozTocId85306"></A>Release 1.1, Friday May 4, 2007</H4>
+		<P>
+			Added support for writing DSA private keys, and more encodings, in OpenSsl 
+			(PemReader/PemWriter).<br>
+			Removed SharpZipLib dependency.<br>
+			Added RSA blinded signature classes.<br>
+			Added Asn1.IsisMtt namespace (ISIS-MTT ASN.1 classes).<br>
+			Added SEED block cipher engine.<br>
+			Added Salsa20 stream cipher engine.<br>
+			Performance optimisations for F2m elliptic curves.<br>
+			Fixed OpenPGP bug decrypting files with multiple types of encryption on the 
+			session key.<br>
+		</P>
+		<H4><A class="mozTocH4" name="mozTocId85305"></A>Release 1.0, Thursday January 18, 
+			2007</H4>
+		<P>
+			Implementations of CMS, OCSP, OpenPGP, and TSP.<br>
+			Elliptic Curves (F2m and Fp).<br>
+			A basic TLS client.<br>
+			PEM file reading and writing.<br>
+			Symmetric key algorithms: Camellia, GOST28147, NaccacheStern, and TEA/XTEA.<br>
+			Symmetric key modes: GOFB and OpenPGPCFB.<br>
+			Symmetric key paddings: ISO7816d4.<br>
+			Asymmetric key algorithms: RSA blinding.<br>
+			Digests: GOST3411 and Whirlpool.<br>
+			Macs: GOST28147 and ISO9797 Alg 3.<br>
+			Signer mechanisms: ECDSA, ECGOST3410, and GOST3410.<br>
+			...and many more features, bug fixes, and performance improvements.<br>
+		</P>
+		<H4><A class="mozTocH4" name="mozTocId85304"></A>Tuesday Febuary 1, 2005</H4>
+		<P>This is the second beta release of the Bouncy Castle API C# implementation.<BR>
+			Reliability improvement to ASN1InputStream.<BR>
+			The OID entries in SignerUtilities for RSA signature algorithms for SHA-256,<BR>
+			SHA-384, and SHA-512 were pointing creating the wrong signature objects.</P>
+		<h4><a class="mozTocH4" name="mozTocId498363"></a>Sunday December 12, 2004</h4>
+		This is the first beta release of the Bouncy Castle Cryptographic API C# 
+		implementation.<br>
+		The Legion of the Bouncy Castle would like to extend their thanks to all those 
+		who contributed to this API during the alpha stages of its development.<br>
+		Keep up the good work folks.<br>
+		Please send any questions or bug reports to <a href="mailto:%5Cdev-crypto-csharp@bouncycastle.org">
+			dev-crypto-csharp@bouncycastle.org</a><br>
+		<br>
+		<hr style="WIDTH: 100%; HEIGHT: 2px">
+		<h3><a class="mozTocH3" name="mozTocId948186"></a>Trademarks.<br>
+		</h3>
+		C#, .NET, and MSDN are Registered Trademarks of Microsoft. <a href="http://www.microsoft.com">
+			Microsoft.com</a><br>
+		Java is a Registered Trademark of Sun Microsystems. <a href="http://www.sun.com">Sun 
+			Microsystems</a><br>
+		<br>
+		<br>
+		<div style="TEXT-ALIGN: center"> 2007 Legion of the Bouncy Castle<br>
+		</div>
+	</body>
+</html>
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
new file mode 100644
index 000000000..7411f0a21
--- /dev/null
+++ b/Crypto/bzip2/src/CBZip2InputStream.cs
@@ -0,0 +1,919 @@
+/*
+ * 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;
+using System.IO;
+
+namespace Org.BouncyCastle.Apache.Bzip2
+{
+	/**
+    * An input stream that decompresses from the BZip2 format (with the file
+    * header chars) to be read as any other stream.
+    *
+    * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+    *
+    * <b>NB:</b> note this class has been modified to read the leading BZ from the
+    * start of the BZIP2 stream to make it compatible with other PGP programs.
+    */
+    public class CBZip2InputStream : Stream 
+	{
+        private static void Cadvise() {
+            //System.out.Println("CRC Error");
+            //throw new CCoruptionError();
+        }
+
+//        private static void BadBGLengths() {
+//            Cadvise();
+//        }
+//
+//        private static void BitStreamEOF() {
+//            Cadvise();
+//        }
+
+        private static void CompressedStreamEOF() {
+            Cadvise();
+        }
+
+        private void MakeMaps() {
+            int i;
+            nInUse = 0;
+            for (i = 0; i < 256; i++) {
+                if (inUse[i]) {
+                    seqToUnseq[nInUse] = (char) i;
+                    unseqToSeq[i] = (char) nInUse;
+                    nInUse++;
+                }
+            }
+        }
+
+        /*
+        index of the last char in the block, so
+        the block size == last + 1.
+        */
+        private int  last;
+
+        /*
+        index in zptr[] of original string after sorting.
+        */
+        private int  origPtr;
+
+        /*
+        always: in the range 0 .. 9.
+        The current block size is 100000 * this number.
+        */
+        private int blockSize100k;
+
+        private bool blockRandomised;
+
+        private int bsBuff;
+        private int bsLive;
+        private CRC mCrc = new CRC();
+
+        private bool[] inUse = new bool[256];
+        private int nInUse;
+
+        private char[] seqToUnseq = new char[256];
+        private char[] unseqToSeq = new char[256];
+
+        private char[] selector = new char[BZip2Constants.MAX_SELECTORS];
+        private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS];
+
+        private int[] tt;
+        private char[] ll8;
+
+        /*
+        freq table collected to save a pass over the data
+        during decompression.
+        */
+        private int[] unzftab = new int[256];
+
+        private int[][] limit = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+        private int[][] basev = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+        private int[][] perm = InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+        private int[] minLens = new int[BZip2Constants.N_GROUPS];
+
+        private Stream bsStream;
+
+        private bool streamEnd = false;
+
+        private int currentChar = -1;
+
+        private const int START_BLOCK_STATE = 1;
+        private const int RAND_PART_A_STATE = 2;
+        private const int RAND_PART_B_STATE = 3;
+        private const int RAND_PART_C_STATE = 4;
+        private const int NO_RAND_PART_A_STATE = 5;
+        private const int NO_RAND_PART_B_STATE = 6;
+        private const int NO_RAND_PART_C_STATE = 7;
+
+        private int currentState = START_BLOCK_STATE;
+
+        private int storedBlockCRC, storedCombinedCRC;
+        private int computedBlockCRC, computedCombinedCRC;
+
+        int i2, count, chPrev, ch2;
+        int i, tPos;
+        int rNToGo = 0;
+        int rTPos  = 0;
+        int j2;
+        char z;
+
+        public CBZip2InputStream(Stream zStream) {
+            ll8 = null;
+            tt = null;
+            BsSetStream(zStream);
+            Initialize();
+            InitBlock();
+            SetupBlock();
+        }
+
+        internal static int[][] InitIntArray(int n1, int n2) {
+            int[][] a = new int[n1][];
+            for (int k = 0; k < n1; ++k) {
+                a[k] = new int[n2];
+            }
+            return a;
+        }
+
+        internal static char[][] InitCharArray(int n1, int n2) {
+            char[][] a = new char[n1][];
+            for (int k = 0; k < n1; ++k) {
+                a[k] = new char[n2];
+            }
+            return a;
+        }
+
+        public override int ReadByte() {
+            if (streamEnd) {
+                return -1;
+            } else {
+                int retChar = currentChar;
+                switch (currentState) {
+                case START_BLOCK_STATE:
+                    break;
+                case RAND_PART_A_STATE:
+                    break;
+                case RAND_PART_B_STATE:
+                    SetupRandPartB();
+                    break;
+                case RAND_PART_C_STATE:
+                    SetupRandPartC();
+                    break;
+                case NO_RAND_PART_A_STATE:
+                    break;
+                case NO_RAND_PART_B_STATE:
+                    SetupNoRandPartB();
+                    break;
+                case NO_RAND_PART_C_STATE:
+                    SetupNoRandPartC();
+                    break;
+                default:
+                    break;
+                }
+                return retChar;
+            }
+        }
+
+        private void Initialize() {
+            char magic3, magic4;
+            magic3 = BsGetUChar();
+            magic4 = BsGetUChar();
+            if (magic3 != 'B' && magic4 != 'Z')
+            {
+                throw new IOException("Not a BZIP2 marked stream");
+            }
+            magic3 = BsGetUChar();
+            magic4 = BsGetUChar();
+            if (magic3 != 'h' || magic4 < '1' || magic4 > '9') {
+                BsFinishedWithStream();
+                streamEnd = true;
+                return;
+            }
+
+            SetDecompressStructureSizes(magic4 - '0');
+            computedCombinedCRC = 0;
+        }
+
+        private void InitBlock() {
+            char magic1, magic2, magic3, magic4;
+            char magic5, magic6;
+            magic1 = BsGetUChar();
+            magic2 = BsGetUChar();
+            magic3 = BsGetUChar();
+            magic4 = BsGetUChar();
+            magic5 = BsGetUChar();
+            magic6 = BsGetUChar();
+            if (magic1 == 0x17 && magic2 == 0x72 && magic3 == 0x45
+                && magic4 == 0x38 && magic5 == 0x50 && magic6 == 0x90) {
+                Complete();
+                return;
+            }
+
+            if (magic1 != 0x31 || magic2 != 0x41 || magic3 != 0x59
+                || magic4 != 0x26 || magic5 != 0x53 || magic6 != 0x59) {
+                BadBlockHeader();
+                streamEnd = true;
+                return;
+            }
+
+            storedBlockCRC = BsGetInt32();
+
+            if (BsR(1) == 1) {
+                blockRandomised = true;
+            } else {
+                blockRandomised = false;
+            }
+
+            //        currBlockNo++;
+            GetAndMoveToFrontDecode();
+
+            mCrc.InitialiseCRC();
+            currentState = START_BLOCK_STATE;
+        }
+
+        private void EndBlock() {
+            computedBlockCRC = mCrc.GetFinalCRC();
+            /* A bad CRC is considered a fatal error. */
+            if (storedBlockCRC != computedBlockCRC) {
+                CrcError();
+            }
+
+            computedCombinedCRC = (computedCombinedCRC << 1)
+                | (int)(((uint)computedCombinedCRC) >> 31);
+            computedCombinedCRC ^= computedBlockCRC;
+        }
+
+        private void Complete() {
+            storedCombinedCRC = BsGetInt32();
+            if (storedCombinedCRC != computedCombinedCRC) {
+                CrcError();
+            }
+
+            BsFinishedWithStream();
+            streamEnd = true;
+        }
+
+        private static void BlockOverrun() {
+            Cadvise();
+        }
+
+        private static void BadBlockHeader() {
+            Cadvise();
+        }
+
+        private static void CrcError() {
+            Cadvise();
+        }
+
+		private void BsFinishedWithStream() {
+            try {
+                if (this.bsStream != null) {
+                    this.bsStream.Dispose();
+                    this.bsStream = null;
+                }
+            } catch {
+                //ignore
+            }
+        }
+
+		private void BsSetStream(Stream f) {
+            bsStream = f;
+            bsLive = 0;
+            bsBuff = 0;
+        }
+
+        private int BsR(int n) {
+            int v;
+            while (bsLive < n) {
+                int zzi;
+                char thech = '\0';
+                try {
+                    thech = (char) bsStream.ReadByte();
+                } catch (IOException) {
+                    CompressedStreamEOF();
+                }
+                if (thech == '\uffff') {
+                    CompressedStreamEOF();
+                }
+                zzi = thech;
+                bsBuff = (bsBuff << 8) | (zzi & 0xff);
+                bsLive += 8;
+            }
+
+            v = (bsBuff >> (bsLive - n)) & ((1 << n) - 1);
+            bsLive -= n;
+            return v;
+        }
+
+        private char BsGetUChar() {
+            return (char) BsR(8);
+        }
+
+        private int BsGetint() {
+            int u = 0;
+            u = (u << 8) | BsR(8);
+            u = (u << 8) | BsR(8);
+            u = (u << 8) | BsR(8);
+            u = (u << 8) | BsR(8);
+            return u;
+        }
+
+        private int BsGetIntVS(int numBits) {
+            return (int) BsR(numBits);
+        }
+
+        private int BsGetInt32() {
+            return (int) BsGetint();
+        }
+
+        private void HbCreateDecodeTables(int[] limit, int[] basev,
+                                        int[] perm, char[] length,
+                                        int minLen, int maxLen, int alphaSize) {
+            int pp, i, j, vec;
+
+            pp = 0;
+            for (i = minLen; i <= maxLen; i++) {
+                for (j = 0; j < alphaSize; j++) {
+                    if (length[j] == i) {
+                        perm[pp] = j;
+                        pp++;
+                    }
+                }
+            }
+
+            for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) {
+                basev[i] = 0;
+            }
+            for (i = 0; i < alphaSize; i++) {
+                basev[length[i] + 1]++;
+            }
+
+            for (i = 1; i < BZip2Constants.MAX_CODE_LEN; i++) {
+                basev[i] += basev[i - 1];
+            }
+
+            for (i = 0; i < BZip2Constants.MAX_CODE_LEN; i++) {
+                limit[i] = 0;
+            }
+            vec = 0;
+
+            for (i = minLen; i <= maxLen; i++) {
+                vec += (basev[i + 1] - basev[i]);
+                limit[i] = vec - 1;
+                vec <<= 1;
+            }
+            for (i = minLen + 1; i <= maxLen; i++) {
+                basev[i] = ((limit[i - 1] + 1) << 1) - basev[i];
+            }
+        }
+
+        private void RecvDecodingTables() {
+            char[][] len = InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+            int i, j, t, nGroups, nSelectors, alphaSize;
+            int minLen, maxLen;
+            bool[] inUse16 = new bool[16];
+
+            /* Receive the mapping table */
+            for (i = 0; i < 16; i++) {
+                if (BsR(1) == 1) {
+                    inUse16[i] = true;
+                } else {
+                    inUse16[i] = false;
+                }
+            }
+
+            for (i = 0; i < 256; i++) {
+                inUse[i] = false;
+            }
+
+            for (i = 0; i < 16; i++) {
+                if (inUse16[i]) {
+                    for (j = 0; j < 16; j++) {
+                        if (BsR(1) == 1) {
+                            inUse[i * 16 + j] = true;
+                        }
+                    }
+                }
+            }
+
+            MakeMaps();
+            alphaSize = nInUse + 2;
+
+            /* Now the selectors */
+            nGroups = BsR(3);
+            nSelectors = BsR(15);
+            for (i = 0; i < nSelectors; i++) {
+                j = 0;
+                while (BsR(1) == 1) {
+                    j++;
+                }
+                selectorMtf[i] = (char) j;
+            }
+
+            /* Undo the MTF values for the selectors. */
+            {
+                char[] pos = new char[BZip2Constants.N_GROUPS];
+                char tmp, v;
+                for (v = '\0'; v < nGroups; v++) {
+                    pos[v] = v;
+                }
+
+                for (i = 0; i < nSelectors; i++) {
+                    v = selectorMtf[i];
+                    tmp = pos[v];
+                    while (v > 0) {
+                        pos[v] = pos[v - 1];
+                        v--;
+                    }
+                    pos[0] = tmp;
+                    selector[i] = tmp;
+                }
+            }
+
+            /* Now the coding tables */
+            for (t = 0; t < nGroups; t++) {
+                int curr = BsR(5);
+                for (i = 0; i < alphaSize; i++) {
+                    while (BsR(1) == 1) {
+                        if (BsR(1) == 0) {
+                            curr++;
+                        } else {
+                            curr--;
+                        }
+                    }
+                    len[t][i] = (char) curr;
+                }
+            }
+
+            /* Create the Huffman decoding tables */
+            for (t = 0; t < nGroups; t++) {
+                minLen = 32;
+                maxLen = 0;
+                for (i = 0; i < alphaSize; i++) {
+                    if (len[t][i] > maxLen) {
+                        maxLen = len[t][i];
+                    }
+                    if (len[t][i] < minLen) {
+                        minLen = len[t][i];
+                    }
+                }
+                HbCreateDecodeTables(limit[t], basev[t], perm[t], len[t], minLen,
+                                    maxLen, alphaSize);
+                minLens[t] = minLen;
+            }
+        }
+
+        private void GetAndMoveToFrontDecode() {
+            char[] yy = new char[256];
+            int i, j, nextSym, limitLast;
+            int EOB, groupNo, groupPos;
+
+            limitLast = BZip2Constants.baseBlockSize * blockSize100k;
+            origPtr = BsGetIntVS(24);
+
+            RecvDecodingTables();
+            EOB = nInUse + 1;
+            groupNo = -1;
+            groupPos = 0;
+
+            /*
+            Setting up the unzftab entries here is not strictly
+            necessary, but it does save having to do it later
+            in a separate pass, and so saves a block's worth of
+            cache misses.
+            */
+            for (i = 0; i <= 255; i++) {
+                unzftab[i] = 0;
+            }
+
+            for (i = 0; i <= 255; i++) {
+                yy[i] = (char) i;
+            }
+
+            last = -1;
+
+            {
+                int zt, zn, zvec, zj;
+                if (groupPos == 0) {
+                    groupNo++;
+                    groupPos = BZip2Constants.G_SIZE;
+                }
+                groupPos--;
+                zt = selector[groupNo];
+                zn = minLens[zt];
+                zvec = BsR(zn);
+                while (zvec > limit[zt][zn]) {
+                    zn++;
+                    {
+                        {
+                            while (bsLive < 1) {
+                                int zzi;
+                                char thech = '\0';
+                                try {
+                                    thech = (char) bsStream.ReadByte();
+                                } catch (IOException) {
+                                    CompressedStreamEOF();
+                                }
+                                if (thech == '\uffff') {
+                                    CompressedStreamEOF();
+                                }
+                                zzi = thech;
+                                bsBuff = (bsBuff << 8) | (zzi & 0xff);
+                                bsLive += 8;
+                            }
+                        }
+                        zj = (bsBuff >> (bsLive - 1)) & 1;
+                        bsLive--;
+                    }
+                    zvec = (zvec << 1) | zj;
+                }
+                nextSym = perm[zt][zvec - basev[zt][zn]];
+            }
+
+            while (true) {
+
+                if (nextSym == EOB) {
+                    break;
+                }
+
+                if (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB) {
+                    char ch;
+                    int s = -1;
+                    int N = 1;
+                    do {
+                        if (nextSym == BZip2Constants.RUNA) {
+                            s = s + (0 + 1) * N;
+                        } else if (nextSym == BZip2Constants.RUNB) {
+                            s = s + (1 + 1) * N;
+                            }
+                        N = N * 2;
+                        {
+                            int zt, zn, zvec, zj;
+                            if (groupPos == 0) {
+                                groupNo++;
+                                groupPos = BZip2Constants.G_SIZE;
+                            }
+                            groupPos--;
+                            zt = selector[groupNo];
+                            zn = minLens[zt];
+                            zvec = BsR(zn);
+                            while (zvec > limit[zt][zn]) {
+                                zn++;
+                                {
+                                    {
+                                        while (bsLive < 1) {
+                                            int zzi;
+                                            char thech = '\0';
+                                            try {
+                                                thech = (char) bsStream.ReadByte();
+                                            } catch (IOException) {
+                                                CompressedStreamEOF();
+                                            }
+                                            if (thech == '\uffff') {
+                                                CompressedStreamEOF();
+                                            }
+                                            zzi = thech;
+                                            bsBuff = (bsBuff << 8) | (zzi & 0xff);
+                                            bsLive += 8;
+                                        }
+                                    }
+                                    zj = (bsBuff >> (bsLive - 1)) & 1;
+                                    bsLive--;
+                                }
+                                zvec = (zvec << 1) | zj;
+                            }
+                            nextSym = perm[zt][zvec - basev[zt][zn]];
+                        }
+                    } while (nextSym == BZip2Constants.RUNA || nextSym == BZip2Constants.RUNB);
+
+                    s++;
+                    ch = seqToUnseq[yy[0]];
+                    unzftab[ch] += s;
+
+                    while (s > 0) {
+                        last++;
+                        ll8[last] = ch;
+                        s--;
+                    }
+
+                    if (last >= limitLast) {
+                        BlockOverrun();
+                    }
+                    continue;
+                } else {
+                    char tmp;
+                    last++;
+                    if (last >= limitLast) {
+                        BlockOverrun();
+                    }
+
+                    tmp = yy[nextSym - 1];
+                    unzftab[seqToUnseq[tmp]]++;
+                    ll8[last] = seqToUnseq[tmp];
+
+                    /*
+                    This loop is hammered during decompression,
+                    hence the unrolling.
+
+                    for (j = nextSym-1; j > 0; j--) yy[j] = yy[j-1];
+                    */
+
+                    j = nextSym - 1;
+                    for (; j > 3; j -= 4) {
+                        yy[j]     = yy[j - 1];
+                        yy[j - 1] = yy[j - 2];
+                        yy[j - 2] = yy[j - 3];
+                        yy[j - 3] = yy[j - 4];
+                    }
+                    for (; j > 0; j--) {
+                        yy[j] = yy[j - 1];
+                    }
+
+                    yy[0] = tmp;
+                    {
+                        int zt, zn, zvec, zj;
+                        if (groupPos == 0) {
+                            groupNo++;
+                            groupPos = BZip2Constants.G_SIZE;
+                        }
+                        groupPos--;
+                        zt = selector[groupNo];
+                        zn = minLens[zt];
+                        zvec = BsR(zn);
+                        while (zvec > limit[zt][zn]) {
+                            zn++;
+                            {
+                                {
+                                    while (bsLive < 1) {
+                                        int zzi;
+                                        char thech = '\0';
+                                        try {
+                                            thech = (char) bsStream.ReadByte();
+                                        } catch (IOException) {
+                                            CompressedStreamEOF();
+                                        }
+                                        zzi = thech;
+                                        bsBuff = (bsBuff << 8) | (zzi & 0xff);
+                                        bsLive += 8;
+                                    }
+                                }
+                                zj = (bsBuff >> (bsLive - 1)) & 1;
+                                bsLive--;
+                            }
+                            zvec = (zvec << 1) | zj;
+                        }
+                        nextSym = perm[zt][zvec - basev[zt][zn]];
+                    }
+                    continue;
+                }
+            }
+        }
+
+        private void SetupBlock() {
+            int[] cftab = new int[257];
+            char ch;
+
+            cftab[0] = 0;
+            for (i = 1; i <= 256; i++) {
+                cftab[i] = unzftab[i - 1];
+            }
+            for (i = 1; i <= 256; i++) {
+                cftab[i] += cftab[i - 1];
+            }
+
+            for (i = 0; i <= last; i++) {
+                ch = (char) ll8[i];
+                tt[cftab[ch]] = i;
+                cftab[ch]++;
+            }
+            cftab = null;
+
+            tPos = tt[origPtr];
+
+            count = 0;
+            i2 = 0;
+            ch2 = 256;   /* not a char and not EOF */
+
+            if (blockRandomised) {
+                rNToGo = 0;
+                rTPos = 0;
+                SetupRandPartA();
+            } else {
+                SetupNoRandPartA();
+            }
+        }
+
+        private void SetupRandPartA() {
+            if (i2 <= last) {
+                chPrev = ch2;
+                ch2 = ll8[tPos];
+                tPos = tt[tPos];
+                if (rNToGo == 0) {
+                    rNToGo = BZip2Constants.rNums[rTPos];
+                    rTPos++;
+                    if (rTPos == 512) {
+                        rTPos = 0;
+                    }
+                }
+                rNToGo--;
+                ch2 ^= (int) ((rNToGo == 1) ? 1 : 0);
+                i2++;
+
+                currentChar = ch2;
+                currentState = RAND_PART_B_STATE;
+                mCrc.UpdateCRC(ch2);
+            } else {
+                EndBlock();
+                InitBlock();
+                SetupBlock();
+            }
+        }
+
+        private void SetupNoRandPartA() {
+            if (i2 <= last) {
+                chPrev = ch2;
+                ch2 = ll8[tPos];
+                tPos = tt[tPos];
+                i2++;
+
+                currentChar = ch2;
+                currentState = NO_RAND_PART_B_STATE;
+                mCrc.UpdateCRC(ch2);
+            } else {
+                EndBlock();
+                InitBlock();
+                SetupBlock();
+            }
+        }
+
+        private void SetupRandPartB() {
+            if (ch2 != chPrev) {
+                currentState = RAND_PART_A_STATE;
+                count = 1;
+                SetupRandPartA();
+            } else {
+                count++;
+                if (count >= 4) {
+                    z = ll8[tPos];
+                    tPos = tt[tPos];
+                    if (rNToGo == 0) {
+                        rNToGo = BZip2Constants.rNums[rTPos];
+                        rTPos++;
+                        if (rTPos == 512) {
+                            rTPos = 0;
+                        }
+                    }
+                    rNToGo--;
+                    z ^= (char)((rNToGo == 1) ? 1 : 0);
+                    j2 = 0;
+                    currentState = RAND_PART_C_STATE;
+                    SetupRandPartC();
+                } else {
+                    currentState = RAND_PART_A_STATE;
+                    SetupRandPartA();
+                }
+            }
+        }
+
+        private void SetupRandPartC() {
+            if (j2 < (int) z) {
+                currentChar = ch2;
+                mCrc.UpdateCRC(ch2);
+                j2++;
+            } else {
+                currentState = RAND_PART_A_STATE;
+                i2++;
+                count = 0;
+                SetupRandPartA();
+            }
+        }
+
+        private void SetupNoRandPartB() {
+            if (ch2 != chPrev) {
+                currentState = NO_RAND_PART_A_STATE;
+                count = 1;
+                SetupNoRandPartA();
+            } else {
+                count++;
+                if (count >= 4) {
+                    z = ll8[tPos];
+                    tPos = tt[tPos];
+                    currentState = NO_RAND_PART_C_STATE;
+                    j2 = 0;
+                    SetupNoRandPartC();
+                } else {
+                    currentState = NO_RAND_PART_A_STATE;
+                    SetupNoRandPartA();
+                }
+            }
+        }
+
+        private void SetupNoRandPartC() {
+            if (j2 < (int) z) {
+                currentChar = ch2;
+                mCrc.UpdateCRC(ch2);
+                j2++;
+            } else {
+                currentState = NO_RAND_PART_A_STATE;
+                i2++;
+                count = 0;
+                SetupNoRandPartA();
+            }
+        }
+
+        private void SetDecompressStructureSizes(int newSize100k) {
+            if (!(0 <= newSize100k && newSize100k <= 9 && 0 <= blockSize100k
+                && blockSize100k <= 9)) {
+                // throw new IOException("Invalid block size");
+            }
+
+            blockSize100k = newSize100k;
+
+            if (newSize100k == 0) {
+                return;
+            }
+
+            int n = BZip2Constants.baseBlockSize * newSize100k;
+            ll8 = new char[n];
+            tt = new int[n];
+        }
+    
+        public override void Flush() {
+        }
+    
+        public override int Read(byte[] buffer, int offset, int count) {
+            int c = -1;
+            int k;
+            for (k = 0; k < count; ++k) {
+                c = ReadByte();
+                if (c == -1)
+                    break;
+                buffer[k + offset] = (byte)c;
+            }
+            return k;
+        }
+    
+        public override long Seek(long offset, SeekOrigin origin) {
+            return 0;
+        }
+    
+        public override void SetLength(long value) {
+        }
+    
+        public override void Write(byte[] buffer, int offset, int count) {
+        }
+    
+        public override bool CanRead {
+            get {
+                return true;
+            }
+        }
+    
+        public override bool CanSeek {
+            get {
+                return false;
+            }
+        }
+    
+        public override bool CanWrite {
+            get {
+                return false;
+            }
+        }
+    
+        public override long Length {
+            get {
+                return 0;
+            }
+        }
+    
+        public override long Position {
+            get {
+                return 0;
+            }
+            set {
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/Crypto/bzip2/src/CBZip2OutputStream.cs b/Crypto/bzip2/src/CBZip2OutputStream.cs
new file mode 100644
index 000000000..2c6bed1df
--- /dev/null
+++ b/Crypto/bzip2/src/CBZip2OutputStream.cs
@@ -0,0 +1,1696 @@
+/*
+ * 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;
+using System.IO;
+
+namespace Org.BouncyCastle.Apache.Bzip2
+{
+	/**
+    * An output stream that compresses into the BZip2 format (with the file
+    * header chars) into another stream.
+    *
+    * @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+    *
+    * TODO:    Update to BZip2 1.0.1
+    * <b>NB:</b> note this class has been modified to add a leading BZ to the
+    * start of the BZIP2 stream to make it compatible with other PGP programs.
+    */
+    public class CBZip2OutputStream : Stream 
+	{
+        protected const int SETMASK = (1 << 21);
+        protected const int CLEARMASK = (~SETMASK);
+        protected const int GREATER_ICOST = 15;
+        protected const int LESSER_ICOST = 0;
+        protected const int SMALL_THRESH = 20;
+        protected const int DEPTH_THRESH = 10;
+
+        /*
+        If you are ever unlucky/improbable enough
+        to get a stack overflow whilst sorting,
+        increase the following constant and try
+        again.  In practice I have never seen the
+        stack go above 27 elems, so the following
+        limit seems very generous.
+        */
+        protected const int QSORT_STACK_SIZE = 1000;
+        private bool finished;
+
+        private static void Panic() {
+            //System.out.Println("panic");
+            //throw new CError();
+        }
+
+        private void MakeMaps() {
+            int i;
+            nInUse = 0;
+            for (i = 0; i < 256; i++) {
+                if (inUse[i]) {
+                    seqToUnseq[nInUse] = (char) i;
+                    unseqToSeq[i] = (char) nInUse;
+                    nInUse++;
+                }
+            }
+        }
+
+        protected static void HbMakeCodeLengths(char[] len, int[] freq,
+                                                int alphaSize, int maxLen) {
+            /*
+            Nodes and heap entries run from 1.  Entry 0
+            for both the heap and nodes is a sentinel.
+            */
+            int nNodes, nHeap, n1, n2, i, j, k;
+            bool  tooLong;
+
+            int[] heap = new int[BZip2Constants.MAX_ALPHA_SIZE + 2];
+            int[] weight = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];
+            int[] parent = new int[BZip2Constants.MAX_ALPHA_SIZE * 2];
+
+            for (i = 0; i < alphaSize; i++) {
+                weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8;
+            }
+
+            while (true) {
+                nNodes = alphaSize;
+                nHeap = 0;
+
+                heap[0] = 0;
+                weight[0] = 0;
+                parent[0] = -2;
+
+                for (i = 1; i <= alphaSize; i++) {
+                    parent[i] = -1;
+                    nHeap++;
+                    heap[nHeap] = i;
+                    {
+                        int zz, tmp;
+                        zz = nHeap;
+                        tmp = heap[zz];
+                        while (weight[tmp] < weight[heap[zz >> 1]]) {
+                            heap[zz] = heap[zz >> 1];
+                            zz >>= 1;
+                        }
+                        heap[zz] = tmp;
+                    }
+                }
+                if (!(nHeap < (BZip2Constants.MAX_ALPHA_SIZE + 2))) {
+                    Panic();
+                }
+
+                while (nHeap > 1) {
+                    n1 = heap[1];
+                    heap[1] = heap[nHeap];
+                    nHeap--;
+                    {
+                        int zz = 0, yy = 0, tmp = 0;
+                        zz = 1;
+                        tmp = heap[zz];
+                        while (true) {
+                            yy = zz << 1;
+                            if (yy > nHeap) {
+                                break;
+                            }
+                            if (yy < nHeap
+                                && weight[heap[yy + 1]] < weight[heap[yy]]) {
+                                yy++;
+                            }
+                            if (weight[tmp] < weight[heap[yy]]) {
+                                break;
+                            }
+                            heap[zz] = heap[yy];
+                            zz = yy;
+                        }
+                        heap[zz] = tmp;
+                    }
+                    n2 = heap[1];
+                    heap[1] = heap[nHeap];
+                    nHeap--;
+                    {
+                        int zz = 0, yy = 0, tmp = 0;
+                        zz = 1;
+                        tmp = heap[zz];
+                        while (true) {
+                            yy = zz << 1;
+                            if (yy > nHeap) {
+                                break;
+                            }
+                            if (yy < nHeap
+                                && weight[heap[yy + 1]] < weight[heap[yy]]) {
+                                yy++;
+                            }
+                            if (weight[tmp] < weight[heap[yy]]) {
+                                break;
+                            }
+                            heap[zz] = heap[yy];
+                            zz = yy;
+                        }
+                        heap[zz] = tmp;
+                    }
+                    nNodes++;
+                    parent[n1] = parent[n2] = nNodes;
+
+                    weight[nNodes] = (int)((uint)((weight[n1] & 0xffffff00)
+                                    + (weight[n2] & 0xffffff00))
+                        | (uint)(1 + (((weight[n1] & 0x000000ff) >
+                                (weight[n2] & 0x000000ff)) ?
+                                (weight[n1] & 0x000000ff) :
+                                (weight[n2] & 0x000000ff))));
+
+                    parent[nNodes] = -1;
+                    nHeap++;
+                    heap[nHeap] = nNodes;
+                    {
+                        int zz = 0, tmp = 0;
+                        zz = nHeap;
+                        tmp = heap[zz];
+                        while (weight[tmp] < weight[heap[zz >> 1]]) {
+                            heap[zz] = heap[zz >> 1];
+                            zz >>= 1;
+                        }
+                        heap[zz] = tmp;
+                    }
+                }
+                if (!(nNodes < (BZip2Constants.MAX_ALPHA_SIZE * 2))) {
+                    Panic();
+                }
+
+                tooLong = false;
+                for (i = 1; i <= alphaSize; i++) {
+                    j = 0;
+                    k = i;
+                    while (parent[k] >= 0) {
+                        k = parent[k];
+                        j++;
+                    }
+                    len[i - 1] = (char) j;
+                    if (j > maxLen) {
+                        tooLong = true;
+                    }
+                }
+
+                if (!tooLong) {
+                    break;
+                }
+
+                for (i = 1; i < alphaSize; i++) {
+                    j = weight[i] >> 8;
+                    j = 1 + (j / 2);
+                    weight[i] = j << 8;
+                }
+            }
+        }
+
+        /*
+        index of the last char in the block, so
+        the block size == last + 1.
+        */
+        int last;
+
+        /*
+        index in zptr[] of original string after sorting.
+        */
+        int origPtr;
+
+        /*
+        always: in the range 0 .. 9.
+        The current block size is 100000 * this number.
+        */
+        int blockSize100k;
+
+        bool blockRandomised;
+
+        int bytesOut;
+        int bsBuff;
+        int bsLive;
+        CRC mCrc = new CRC();
+
+        private bool[] inUse = new bool[256];
+        private int nInUse;
+
+        private char[] seqToUnseq = new char[256];
+        private char[] unseqToSeq = new char[256];
+
+        private char[] selector = new char[BZip2Constants.MAX_SELECTORS];
+        private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS];
+
+        private char[] block;
+        private int[] quadrant;
+        private int[] zptr;
+        private short[] szptr;
+        private int[] ftab;
+
+        private int nMTF;
+
+        private int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE];
+
+        /*
+        * Used when sorting.  If too many long comparisons
+        * happen, we stop sorting, randomise the block
+        * slightly, and try again.
+        */
+        private int workFactor;
+        private int workDone;
+        private int workLimit;
+        private bool firstAttempt;
+        private int nBlocksRandomised;
+
+        private int currentChar = -1;
+        private int runLength = 0;
+
+        public CBZip2OutputStream(Stream inStream) : this(inStream, 9) {
+        }
+
+        public CBZip2OutputStream(Stream inStream, int inBlockSize)
+            {
+            block = null;
+            quadrant = null;
+            zptr = null;
+            ftab = null;
+
+            inStream.WriteByte((byte)'B');
+            inStream.WriteByte((byte)'Z');
+
+            BsSetStream(inStream);
+
+            workFactor = 50;
+            if (inBlockSize > 9) {
+                inBlockSize = 9;
+            }
+            if (inBlockSize < 1) {
+                inBlockSize = 1;
+            }
+            blockSize100k = inBlockSize;
+            AllocateCompressStructures();
+            Initialize();
+            InitBlock();
+        }
+
+        /**
+        *
+        * modified by Oliver Merkel, 010128
+        *
+        */
+        public override void WriteByte(byte bv) {
+            int b = (256 + bv) % 256;
+            if (currentChar != -1) {
+                if (currentChar == b) {
+                    runLength++;
+                    if (runLength > 254) {
+                        WriteRun();
+                        currentChar = -1;
+                        runLength = 0;
+                    }
+                } else {
+                    WriteRun();
+                    runLength = 1;
+                    currentChar = b;
+                }
+            } else {
+                currentChar = b;
+                runLength++;
+            }
+        }
+
+        private void WriteRun() {
+            if (last < allowableBlockSize) {
+                inUse[currentChar] = true;
+                for (int i = 0; i < runLength; i++) {
+                    mCrc.UpdateCRC((char) currentChar);
+                }
+                switch (runLength) {
+                case 1:
+                    last++;
+                    block[last + 1] = (char) currentChar;
+                    break;
+                case 2:
+                    last++;
+                    block[last + 1] = (char) currentChar;
+                    last++;
+                    block[last + 1] = (char) currentChar;
+                    break;
+                case 3:
+                    last++;
+                    block[last + 1] = (char) currentChar;
+                    last++;
+                    block[last + 1] = (char) currentChar;
+                    last++;
+                    block[last + 1] = (char) currentChar;
+                    break;
+                default:
+                    inUse[runLength - 4] = true;
+                    last++;
+                    block[last + 1] = (char) currentChar;
+                    last++;
+                    block[last + 1] = (char) currentChar;
+                    last++;
+                    block[last + 1] = (char) currentChar;
+                    last++;
+                    block[last + 1] = (char) currentChar;
+                    last++;
+                    block[last + 1] = (char) (runLength - 4);
+                    break;
+                }
+            } else {
+                EndBlock();
+                InitBlock();
+                WriteRun();
+            }
+        }
+
+        bool closed = false;
+
+//        protected void Finalize() {
+//            Close();
+//        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                if (closed)
+                {
+                    return;
+                }
+
+                Finish();
+
+                closed = true;
+                base.Dispose(disposing);
+                bsStream.Dispose();
+            }
+        }
+
+        public void Finish() {
+            if (finished) {
+                return;
+            }
+
+            if (runLength > 0) {
+                WriteRun();
+            }
+            currentChar = -1;
+            EndBlock();
+            EndCompression();
+            finished = true;
+            Flush();
+        }
+        
+        public override void Flush() {
+            bsStream.Flush();
+        }
+
+        private int blockCRC, combinedCRC;
+
+        private void Initialize() {
+            bytesOut = 0;
+            nBlocksRandomised = 0;
+
+            /* Write `magic' bytes h indicating file-format == huffmanised,
+            followed by a digit indicating blockSize100k.
+            */
+            BsPutUChar('h');
+            BsPutUChar('0' + blockSize100k);
+
+            combinedCRC = 0;
+        }
+
+        private int allowableBlockSize;
+
+        private void InitBlock() {
+            //        blockNo++;
+            mCrc.InitialiseCRC();
+            last = -1;
+            //        ch = 0;
+
+            for (int i = 0; i < 256; i++) {
+                inUse[i] = false;
+            }
+
+            /* 20 is just a paranoia constant */
+            allowableBlockSize = BZip2Constants.baseBlockSize * blockSize100k - 20;
+        }
+
+        private void EndBlock() {
+            blockCRC = mCrc.GetFinalCRC();
+            combinedCRC = (combinedCRC << 1) | (int)(((uint)combinedCRC) >> 31);
+            combinedCRC ^= blockCRC;
+
+            /* sort the block and establish posn of original string */
+            DoReversibleTransformation();
+
+            /*
+            A 6-byte block header, the value chosen arbitrarily
+            as 0x314159265359 :-).  A 32 bit value does not really
+            give a strong enough guarantee that the value will not
+            appear by chance in the compressed datastream.  Worst-case
+            probability of this event, for a 900k block, is about
+            2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48 bits.
+            For a compressed file of size 100Gb -- about 100000 blocks --
+            only a 48-bit marker will do.  NB: normal compression/
+            decompression do *not* rely on these statistical properties.
+            They are only important when trying to recover blocks from
+            damaged files.
+            */
+            BsPutUChar(0x31);
+            BsPutUChar(0x41);
+            BsPutUChar(0x59);
+            BsPutUChar(0x26);
+            BsPutUChar(0x53);
+            BsPutUChar(0x59);
+
+            /* Now the block's CRC, so it is in a known place. */
+            BsPutint(blockCRC);
+
+            /* Now a single bit indicating randomisation. */
+            if (blockRandomised) {
+                BsW(1, 1);
+                nBlocksRandomised++;
+            } else {
+                BsW(1, 0);
+            }
+
+            /* Finally, block's contents proper. */
+            MoveToFrontCodeAndSend();
+        }
+
+        private void EndCompression() {
+            /*
+            Now another magic 48-bit number, 0x177245385090, to
+            indicate the end of the last block.  (Sqrt(pi), if
+            you want to know.  I did want to use e, but it contains
+            too much repetition -- 27 18 28 18 28 46 -- for me
+            to feel statistically comfortable.  Call me paranoid.)
+            */
+            BsPutUChar(0x17);
+            BsPutUChar(0x72);
+            BsPutUChar(0x45);
+            BsPutUChar(0x38);
+            BsPutUChar(0x50);
+            BsPutUChar(0x90);
+
+            BsPutint(combinedCRC);
+
+            BsFinishedWithStream();
+        }
+
+        private void HbAssignCodes(int[] code, char[] length, int minLen,
+                                    int maxLen, int alphaSize) {
+            int n, vec, i;
+
+            vec = 0;
+            for (n = minLen; n <= maxLen; n++) {
+                for (i = 0; i < alphaSize; i++) {
+                    if (length[i] == n) {
+                        code[i] = vec;
+                        vec++;
+                    }
+                };
+                vec <<= 1;
+            }
+        }
+
+        private void BsSetStream(Stream f) {
+            bsStream = f;
+            bsLive = 0;
+            bsBuff = 0;
+            bytesOut = 0;
+        }
+
+        private void BsFinishedWithStream() {
+            while (bsLive > 0) {
+                int ch = (bsBuff >> 24);
+                try {
+                    bsStream.WriteByte((byte)ch); // write 8-bit
+                } catch (IOException e) {
+                    throw  e;
+                }
+                bsBuff <<= 8;
+                bsLive -= 8;
+                bytesOut++;
+            }
+        }
+
+        private void BsW(int n, int v) {
+            while (bsLive >= 8) {
+                int ch = (bsBuff >> 24);
+                try {
+                    bsStream.WriteByte((byte)ch); // write 8-bit
+                } catch (IOException e) {
+                    throw e;
+                }
+                bsBuff <<= 8;
+                bsLive -= 8;
+                bytesOut++;
+            }
+            bsBuff |= (v << (32 - bsLive - n));
+            bsLive += n;
+        }
+
+        private void BsPutUChar(int c) {
+            BsW(8, c);
+        }
+
+        private void BsPutint(int u) {
+            BsW(8, (u >> 24) & 0xff);
+            BsW(8, (u >> 16) & 0xff);
+            BsW(8, (u >>  8) & 0xff);
+            BsW(8,  u        & 0xff);
+        }
+
+        private void BsPutIntVS(int numBits, int c) {
+            BsW(numBits, c);
+        }
+
+        private void SendMTFValues() {
+            char[][] len = CBZip2InputStream.InitCharArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+
+            int v, t, i, j, gs, ge, totc, bt, bc, iter;
+            int nSelectors = 0, alphaSize, minLen, maxLen, selCtr;
+            int nGroups;
+
+            alphaSize = nInUse + 2;
+            for (t = 0; t < BZip2Constants.N_GROUPS; t++) {
+                for (v = 0; v < alphaSize; v++) {
+                    len[t][v] = (char) GREATER_ICOST;
+                }
+            }
+
+            /* Decide how many coding tables to use */
+            if (nMTF <= 0) {
+                Panic();
+            }
+
+            if (nMTF < 200) {
+                nGroups = 2;
+            } else if (nMTF < 600) {
+                nGroups = 3;
+            } else if (nMTF < 1200) {
+                nGroups = 4;
+            } else if (nMTF < 2400) {
+                nGroups = 5;
+            } else {
+                nGroups = 6;
+            }
+
+            /* Generate an initial set of coding tables */ {
+                int nPart, remF, tFreq, aFreq;
+
+                nPart = nGroups;
+                remF  = nMTF;
+                gs = 0;
+                while (nPart > 0) {
+                    tFreq = remF / nPart;
+                    ge = gs - 1;
+                    aFreq = 0;
+                    while (aFreq < tFreq && ge < alphaSize - 1) {
+                        ge++;
+                        aFreq += mtfFreq[ge];
+                    }
+
+                    if (ge > gs && nPart != nGroups && nPart != 1
+                        && ((nGroups - nPart) % 2 == 1)) {
+                        aFreq -= mtfFreq[ge];
+                        ge--;
+                    }
+
+                    for (v = 0; v < alphaSize; v++) {
+                        if (v >= gs && v <= ge) {
+                            len[nPart - 1][v] = (char) LESSER_ICOST;
+                        } else {
+                            len[nPart - 1][v] = (char) GREATER_ICOST;
+                        }
+                    }
+
+                    nPart--;
+                    gs = ge + 1;
+                    remF -= aFreq;
+                }
+            }
+
+            int[][] rfreq = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+            int[] fave = new int[BZip2Constants.N_GROUPS];
+            short[] cost = new short[BZip2Constants.N_GROUPS];
+            /*
+            Iterate up to N_ITERS times to improve the tables.
+            */
+            for (iter = 0; iter < BZip2Constants.N_ITERS; iter++) {
+                for (t = 0; t < nGroups; t++) {
+                    fave[t] = 0;
+                }
+
+                for (t = 0; t < nGroups; t++) {
+                    for (v = 0; v < alphaSize; v++) {
+                        rfreq[t][v] = 0;
+                    }
+                }
+
+                nSelectors = 0;
+                totc = 0;
+                gs = 0;
+                while (true) {
+
+                    /* Set group start & end marks. */
+                    if (gs >= nMTF) {
+                        break;
+                    }
+                    ge = gs + BZip2Constants.G_SIZE - 1;
+                    if (ge >= nMTF) {
+                        ge = nMTF - 1;
+                    }
+
+                    /*
+                    Calculate the cost of this group as coded
+                    by each of the coding tables.
+                    */
+                    for (t = 0; t < nGroups; t++) {
+                        cost[t] = 0;
+                    }
+
+                    if (nGroups == 6) {
+                        short cost0, cost1, cost2, cost3, cost4, cost5;
+                        cost0 = cost1 = cost2 = cost3 = cost4 = cost5 = 0;
+                        for (i = gs; i <= ge; i++) {
+                            short icv = szptr[i];
+                            cost0 += (short)len[0][icv];
+                            cost1 += (short)len[1][icv];
+                            cost2 += (short)len[2][icv];
+                            cost3 += (short)len[3][icv];
+                            cost4 += (short)len[4][icv];
+                            cost5 += (short)len[5][icv];
+                        }
+                        cost[0] = cost0;
+                        cost[1] = cost1;
+                        cost[2] = cost2;
+                        cost[3] = cost3;
+                        cost[4] = cost4;
+                        cost[5] = cost5;
+                    } else {
+                        for (i = gs; i <= ge; i++) {
+                            short icv = szptr[i];
+                            for (t = 0; t < nGroups; t++) {
+                                cost[t] += (short)len[t][icv];
+                            }
+                        }
+                    }
+
+                    /*
+                    Find the coding table which is best for this group,
+                    and record its identity in the selector table.
+                    */
+                    bc = 999999999;
+                    bt = -1;
+                    for (t = 0; t < nGroups; t++) {
+                        if (cost[t] < bc) {
+                            bc = cost[t];
+                            bt = t;
+                        }
+                    };
+                    totc += bc;
+                    fave[bt]++;
+                    selector[nSelectors] = (char) bt;
+                    nSelectors++;
+
+                    /*
+                    Increment the symbol frequencies for the selected table.
+                    */
+                    for (i = gs; i <= ge; i++) {
+                        rfreq[bt][szptr[i]]++;
+                    }
+
+                    gs = ge + 1;
+                }
+
+                /*
+                Recompute the tables based on the accumulated frequencies.
+                */
+                for (t = 0; t < nGroups; t++) {
+                    HbMakeCodeLengths(len[t], rfreq[t], alphaSize, 20);
+                }
+            }
+
+            rfreq = null;
+            fave = null;
+            cost = null;
+
+            if (!(nGroups < 8)) {
+                Panic();
+            }
+            if (!(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZip2Constants.G_SIZE)))) {
+                Panic();
+            }
+
+
+            /* Compute MTF values for the selectors. */
+            {
+                char[] pos = new char[BZip2Constants.N_GROUPS];
+                char ll_i, tmp2, tmp;
+                for (i = 0; i < nGroups; i++) {
+                    pos[i] = (char) i;
+                }
+                for (i = 0; i < nSelectors; i++) {
+                    ll_i = selector[i];
+                    j = 0;
+                    tmp = pos[j];
+                    while (ll_i != tmp) {
+                        j++;
+                        tmp2 = tmp;
+                        tmp = pos[j];
+                        pos[j] = tmp2;
+                    }
+                    pos[0] = tmp;
+                    selectorMtf[i] = (char) j;
+                }
+            }
+
+            int[][] code = CBZip2InputStream.InitIntArray(BZip2Constants.N_GROUPS, BZip2Constants.MAX_ALPHA_SIZE);
+
+            /* Assign actual codes for the tables. */
+            for (t = 0; t < nGroups; t++) {
+                minLen = 32;
+                maxLen = 0;
+                for (i = 0; i < alphaSize; i++) {
+                    if (len[t][i] > maxLen) {
+                        maxLen = len[t][i];
+                    }
+                    if (len[t][i] < minLen) {
+                        minLen = len[t][i];
+                    }
+                }
+                if (maxLen > 20) {
+                    Panic();
+                }
+                if (minLen < 1) {
+                    Panic();
+                }
+                HbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize);
+            }
+
+            /* Transmit the mapping table. */
+            {
+                bool[] inUse16 = new bool[16];
+                for (i = 0; i < 16; i++) {
+                    inUse16[i] = false;
+                    for (j = 0; j < 16; j++) {
+                        if (inUse[i * 16 + j]) {
+                            inUse16[i] = true;
+                        }
+                    }
+                }
+
+				for (i = 0; i < 16; i++) {
+                    if (inUse16[i]) {
+                        BsW(1, 1);
+                    } else {
+                        BsW(1, 0);
+                    }
+                }
+
+                for (i = 0; i < 16; i++) {
+                    if (inUse16[i]) {
+                        for (j = 0; j < 16; j++) {
+                            if (inUse[i * 16 + j]) {
+                                BsW(1, 1);
+                            } else {
+                                BsW(1, 0);
+                            }
+                        }
+                    }
+                }
+
+            }
+
+            /* Now the selectors. */
+            BsW(3, nGroups);
+            BsW(15, nSelectors);
+            for (i = 0; i < nSelectors; i++) {
+                for (j = 0; j < selectorMtf[i]; j++) {
+                    BsW(1, 1);
+                }
+                BsW(1, 0);
+            }
+
+            /* Now the coding tables. */
+            for (t = 0; t < nGroups; t++) {
+                int curr = len[t][0];
+                BsW(5, curr);
+                for (i = 0; i < alphaSize; i++) {
+                    while (curr < len[t][i]) {
+                        BsW(2, 2);
+                        curr++; /* 10 */
+                    }
+                    while (curr > len[t][i]) {
+                        BsW(2, 3);
+                        curr--; /* 11 */
+                    }
+                    BsW(1, 0);
+                }
+            }
+
+            /* And finally, the block data proper */
+            selCtr = 0;
+            gs = 0;
+            while (true) {
+                if (gs >= nMTF) {
+                    break;
+                }
+                ge = gs + BZip2Constants.G_SIZE - 1;
+                if (ge >= nMTF) {
+                    ge = nMTF - 1;
+                }
+                for (i = gs; i <= ge; i++) {
+                    BsW(len[selector[selCtr]][szptr[i]],
+                        code[selector[selCtr]][szptr[i]]);
+                }
+
+                gs = ge + 1;
+                selCtr++;
+            }
+            if (!(selCtr == nSelectors)) {
+                Panic();
+            }
+        }
+
+        private void MoveToFrontCodeAndSend() {
+            BsPutIntVS(24, origPtr);
+            GenerateMTFValues();
+            SendMTFValues();
+        }
+
+        private Stream bsStream;
+
+        private void SimpleSort(int lo, int hi, int d) {
+            int i, j, h, bigN, hp;
+            int v;
+
+            bigN = hi - lo + 1;
+            if (bigN < 2) {
+                return;
+            }
+
+            hp = 0;
+            while (incs[hp] < bigN) {
+                hp++;
+            }
+            hp--;
+
+            for (; hp >= 0; hp--) {
+                h = incs[hp];
+
+                i = lo + h;
+                while (true) {
+                    /* copy 1 */
+                    if (i > hi) {
+                        break;
+                    }
+                    v = zptr[i];
+                    j = i;
+                    while (FullGtU(zptr[j - h] + d, v + d)) {
+                        zptr[j] = zptr[j - h];
+                        j = j - h;
+                        if (j <= (lo + h - 1)) {
+                            break;
+                        }
+                    }
+                    zptr[j] = v;
+                    i++;
+
+                    /* copy 2 */
+                    if (i > hi) {
+                        break;
+                    }
+                    v = zptr[i];
+                    j = i;
+                    while (FullGtU(zptr[j - h] + d, v + d)) {
+                        zptr[j] = zptr[j - h];
+                        j = j - h;
+                        if (j <= (lo + h - 1)) {
+                            break;
+                        }
+                    }
+                    zptr[j] = v;
+                    i++;
+
+                    /* copy 3 */
+                    if (i > hi) {
+                        break;
+                    }
+                    v = zptr[i];
+                    j = i;
+                    while (FullGtU(zptr[j - h] + d, v + d)) {
+                        zptr[j] = zptr[j - h];
+                        j = j - h;
+                        if (j <= (lo + h - 1)) {
+                            break;
+                        }
+                    }
+                    zptr[j] = v;
+                    i++;
+
+                    if (workDone > workLimit && firstAttempt) {
+                        return;
+                    }
+                }
+            }
+        }
+
+        private void Vswap(int p1, int p2, int n) {
+            int temp = 0;
+            while (n > 0) {
+                temp = zptr[p1];
+                zptr[p1] = zptr[p2];
+                zptr[p2] = temp;
+                p1++;
+                p2++;
+                n--;
+            }
+        }
+
+        private char Med3(char a, char b, char c) {
+            char t;
+            if (a > b) {
+                t = a;
+                a = b;
+                b = t;
+            }
+            if (b > c) {
+                t = b;
+                b = c;
+                c = t;
+            }
+            if (a > b) {
+                b = a;
+            }
+            return b;
+        }
+
+        internal class StackElem {
+            internal int ll;
+            internal int hh;
+            internal int dd;
+        }
+
+        private void QSort3(int loSt, int hiSt, int dSt) {
+            int unLo, unHi, ltLo, gtHi, med, n, m;
+            int sp, lo, hi, d;
+            StackElem[] stack = new StackElem[QSORT_STACK_SIZE];
+            for (int count = 0; count < QSORT_STACK_SIZE; count++) {
+                stack[count] = new StackElem();
+            }
+
+            sp = 0;
+
+            stack[sp].ll = loSt;
+            stack[sp].hh = hiSt;
+            stack[sp].dd = dSt;
+            sp++;
+
+            while (sp > 0) {
+                if (sp >= QSORT_STACK_SIZE) {
+                    Panic();
+                }
+
+                sp--;
+                lo = stack[sp].ll;
+                hi = stack[sp].hh;
+                d = stack[sp].dd;
+
+                if (hi - lo < SMALL_THRESH || d > DEPTH_THRESH) {
+                    SimpleSort(lo, hi, d);
+                    if (workDone > workLimit && firstAttempt) {
+                        return;
+                    }
+                    continue;
+                }
+
+                med = Med3(block[zptr[lo] + d + 1],
+                        block[zptr[hi            ] + d  + 1],
+                        block[zptr[(lo + hi) >> 1] + d + 1]);
+
+                unLo = ltLo = lo;
+                unHi = gtHi = hi;
+
+                while (true) {
+                    while (true) {
+                        if (unLo > unHi) {
+                            break;
+                        }
+                        n = ((int) block[zptr[unLo] + d + 1]) - med;
+                        if (n == 0) {
+                            int temp = 0;
+                            temp = zptr[unLo];
+                            zptr[unLo] = zptr[ltLo];
+                            zptr[ltLo] = temp;
+                            ltLo++;
+                            unLo++;
+                            continue;
+                        };
+                        if (n >  0) {
+                            break;
+                        }
+                        unLo++;
+                    }
+                    while (true) {
+                        if (unLo > unHi) {
+                            break;
+                        }
+                        n = ((int) block[zptr[unHi] + d + 1]) - med;
+                        if (n == 0) {
+                            int temp = 0;
+                            temp = zptr[unHi];
+                            zptr[unHi] = zptr[gtHi];
+                            zptr[gtHi] = temp;
+                            gtHi--;
+                            unHi--;
+                            continue;
+                        };
+                        if (n <  0) {
+                            break;
+                        }
+                        unHi--;
+                    }
+                    if (unLo > unHi) {
+                        break;
+                    }
+                    int tempx = zptr[unLo];
+                    zptr[unLo] = zptr[unHi];
+                    zptr[unHi] = tempx;
+                    unLo++;
+                    unHi--;
+                }
+
+                if (gtHi < ltLo) {
+                    stack[sp].ll = lo;
+                    stack[sp].hh = hi;
+                    stack[sp].dd = d + 1;
+                    sp++;
+                    continue;
+                }
+
+                n = ((ltLo - lo) < (unLo - ltLo)) ? (ltLo - lo) : (unLo - ltLo);
+                Vswap(lo, unLo - n, n);
+                m = ((hi - gtHi) < (gtHi - unHi)) ? (hi - gtHi) : (gtHi - unHi);
+                Vswap(unLo, hi - m + 1, m);
+
+                n = lo + unLo - ltLo - 1;
+                m = hi - (gtHi - unHi) + 1;
+
+                stack[sp].ll = lo;
+                stack[sp].hh = n;
+                stack[sp].dd = d;
+                sp++;
+
+                stack[sp].ll = n + 1;
+                stack[sp].hh = m - 1;
+                stack[sp].dd = d + 1;
+                sp++;
+
+                stack[sp].ll = m;
+                stack[sp].hh = hi;
+                stack[sp].dd = d;
+                sp++;
+            }
+        }
+
+        private void MainSort() {
+            int i, j, ss, sb;
+            int[] runningOrder = new int[256];
+            int[] copy = new int[256];
+            bool[] bigDone = new bool[256];
+            int c1, c2;
+            int numQSorted;
+
+            /*
+            In the various block-sized structures, live data runs
+            from 0 to last+NUM_OVERSHOOT_BYTES inclusive.  First,
+            set up the overshoot area for block.
+            */
+
+            //   if (verbosity >= 4) fprintf ( stderr, "   sort initialise ...\n" );
+            for (i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {
+                block[last + i + 2] = block[(i % (last + 1)) + 1];
+            }
+            for (i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {
+                quadrant[i] = 0;
+            }
+
+            block[0] = (char) (block[last + 1]);
+
+            if (last < 4000) {
+                /*
+                Use SimpleSort(), since the full sorting mechanism
+                has quite a large constant overhead.
+                */
+                for (i = 0; i <= last; i++) {
+                    zptr[i] = i;
+                }
+                firstAttempt = false;
+                workDone = workLimit = 0;
+                SimpleSort(0, last, 0);
+            } else {
+                numQSorted = 0;
+                for (i = 0; i <= 255; i++) {
+                    bigDone[i] = false;
+                }
+
+                for (i = 0; i <= 65536; i++) {
+                    ftab[i] = 0;
+                }
+
+                c1 = block[0];
+                for (i = 0; i <= last; i++) {
+                    c2 = block[i + 1];
+                    ftab[(c1 << 8) + c2]++;
+                    c1 = c2;
+                }
+
+                for (i = 1; i <= 65536; i++) {
+                    ftab[i] += ftab[i - 1];
+                }
+
+                c1 = block[1];
+                for (i = 0; i < last; i++) {
+                    c2 = block[i + 2];
+                    j = (c1 << 8) + c2;
+                    c1 = c2;
+                    ftab[j]--;
+                    zptr[ftab[j]] = i;
+                }
+
+                j = ((block[last + 1]) << 8) + (block[1]);
+                ftab[j]--;
+                zptr[ftab[j]] = last;
+
+                /*
+                Now ftab contains the first loc of every small bucket.
+                Calculate the running order, from smallest to largest
+                big bucket.
+                */
+
+                for (i = 0; i <= 255; i++) {
+                    runningOrder[i] = i;
+                }
+
+                {
+                    int vv;
+                    int h = 1;
+                    do {
+                        h = 3 * h + 1;
+                    }
+                    while (h <= 256);
+                    do {
+                        h = h / 3;
+                        for (i = h; i <= 255; i++) {
+                            vv = runningOrder[i];
+                            j = i;
+                            while ((ftab[((runningOrder[j - h]) + 1) << 8]
+                                    - ftab[(runningOrder[j - h]) << 8]) >
+                                (ftab[((vv) + 1) << 8] - ftab[(vv) << 8])) {
+                                runningOrder[j] = runningOrder[j - h];
+                                j = j - h;
+                                if (j <= (h - 1)) {
+                                    break;
+                                }
+                            }
+                            runningOrder[j] = vv;
+                        }
+                    } while (h != 1);
+                }
+
+                /*
+                The main sorting loop.
+                */
+                for (i = 0; i <= 255; i++) {
+
+                    /*
+                    Process big buckets, starting with the least full.
+                    */
+                    ss = runningOrder[i];
+
+                    /*
+                    Complete the big bucket [ss] by quicksorting
+                    any unsorted small buckets [ss, j].  Hopefully
+                    previous pointer-scanning phases have already
+                    completed many of the small buckets [ss, j], so
+                    we don't have to sort them at all.
+                    */
+                    for (j = 0; j <= 255; j++) {
+                        sb = (ss << 8) + j;
+                        if (!((ftab[sb] & SETMASK) == SETMASK)) {
+                            int lo = ftab[sb] & CLEARMASK;
+                            int hi = (ftab[sb + 1] & CLEARMASK) - 1;
+                            if (hi > lo) {
+                                QSort3(lo, hi, 2);
+                                numQSorted += (hi - lo + 1);
+                                if (workDone > workLimit && firstAttempt) {
+                                    return;
+                                }
+                            }
+                            ftab[sb] |= SETMASK;
+                        }
+                    }
+
+                    /*
+                    The ss big bucket is now done.  Record this fact,
+                    and update the quadrant descriptors.  Remember to
+                    update quadrants in the overshoot area too, if
+                    necessary.  The "if (i < 255)" test merely skips
+                    this updating for the last bucket processed, since
+                    updating for the last bucket is pointless.
+                    */
+                    bigDone[ss] = true;
+
+                    if (i < 255) {
+                        int bbStart  = ftab[ss << 8] & CLEARMASK;
+                        int bbSize   = (ftab[(ss + 1) << 8] & CLEARMASK) - bbStart;
+                        int shifts   = 0;
+
+                        while ((bbSize >> shifts) > 65534) {
+                            shifts++;
+                        }
+
+                        for (j = 0; j < bbSize; j++) {
+                            int a2update = zptr[bbStart + j];
+                            int qVal = (j >> shifts);
+                            quadrant[a2update] = qVal;
+                            if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) {
+                                quadrant[a2update + last + 1] = qVal;
+                            }
+                        }
+
+                        if (!(((bbSize - 1) >> shifts) <= 65535)) {
+                            Panic();
+                        }
+                    }
+
+                    /*
+                    Now scan this big bucket so as to synthesise the
+                    sorted order for small buckets [t, ss] for all t != ss.
+                    */
+                    for (j = 0; j <= 255; j++) {
+                        copy[j] = ftab[(j << 8) + ss] & CLEARMASK;
+                    }
+
+                    for (j = ftab[ss << 8] & CLEARMASK;
+                        j < (ftab[(ss + 1) << 8] & CLEARMASK); j++) {
+                        c1 = block[zptr[j]];
+                        if (!bigDone[c1]) {
+                            zptr[copy[c1]] = zptr[j] == 0 ? last : zptr[j] - 1;
+                            copy[c1]++;
+                        }
+                    }
+
+                    for (j = 0; j <= 255; j++) {
+                        ftab[(j << 8) + ss] |= SETMASK;
+                    }
+                }
+            }
+        }
+
+        private void RandomiseBlock() {
+            int i;
+            int rNToGo = 0;
+            int rTPos  = 0;
+            for (i = 0; i < 256; i++) {
+                inUse[i] = false;
+            }
+
+            for (i = 0; i <= last; i++) {
+                if (rNToGo == 0) {
+                    rNToGo = (char) BZip2Constants.rNums[rTPos];
+                    rTPos++;
+                    if (rTPos == 512) {
+                        rTPos = 0;
+                    }
+                }
+                rNToGo--;
+                block[i + 1] ^= (char)((rNToGo == 1) ? 1 : 0);
+                // handle 16 bit signed numbers
+                block[i + 1] &= (char)0xFF;
+
+                inUse[block[i + 1]] = true;
+            }
+        }
+
+        private void DoReversibleTransformation() {
+            int i;
+
+            workLimit = workFactor * last;
+            workDone = 0;
+            blockRandomised = false;
+            firstAttempt = true;
+
+            MainSort();
+
+            if (workDone > workLimit && firstAttempt) {
+                RandomiseBlock();
+                workLimit = workDone = 0;
+                blockRandomised = true;
+                firstAttempt = false;
+                MainSort();
+            }
+
+            origPtr = -1;
+            for (i = 0; i <= last; i++) {
+                if (zptr[i] == 0) {
+                    origPtr = i;
+                    break;
+                }
+            };
+
+            if (origPtr == -1) {
+                Panic();
+            }
+        }
+
+        private bool FullGtU(int i1, int i2) {
+            int k;
+            char c1, c2;
+            int s1, s2;
+
+            c1 = block[i1 + 1];
+            c2 = block[i2 + 1];
+            if (c1 != c2) {
+                return (c1 > c2);
+            }
+            i1++;
+            i2++;
+
+            c1 = block[i1 + 1];
+            c2 = block[i2 + 1];
+            if (c1 != c2) {
+                return (c1 > c2);
+            }
+            i1++;
+            i2++;
+
+            c1 = block[i1 + 1];
+            c2 = block[i2 + 1];
+            if (c1 != c2) {
+                return (c1 > c2);
+            }
+            i1++;
+            i2++;
+
+            c1 = block[i1 + 1];
+            c2 = block[i2 + 1];
+            if (c1 != c2) {
+                return (c1 > c2);
+            }
+            i1++;
+            i2++;
+
+            c1 = block[i1 + 1];
+            c2 = block[i2 + 1];
+            if (c1 != c2) {
+                return (c1 > c2);
+            }
+            i1++;
+            i2++;
+
+            c1 = block[i1 + 1];
+            c2 = block[i2 + 1];
+            if (c1 != c2) {
+                return (c1 > c2);
+            }
+            i1++;
+            i2++;
+
+            k = last + 1;
+
+            do {
+                c1 = block[i1 + 1];
+                c2 = block[i2 + 1];
+                if (c1 != c2) {
+                    return (c1 > c2);
+                }
+                s1 = quadrant[i1];
+                s2 = quadrant[i2];
+                if (s1 != s2) {
+                    return (s1 > s2);
+                }
+                i1++;
+                i2++;
+
+                c1 = block[i1 + 1];
+                c2 = block[i2 + 1];
+                if (c1 != c2) {
+                    return (c1 > c2);
+                }
+                s1 = quadrant[i1];
+                s2 = quadrant[i2];
+                if (s1 != s2) {
+                    return (s1 > s2);
+                }
+                i1++;
+                i2++;
+
+                c1 = block[i1 + 1];
+                c2 = block[i2 + 1];
+                if (c1 != c2) {
+                    return (c1 > c2);
+                }
+                s1 = quadrant[i1];
+                s2 = quadrant[i2];
+                if (s1 != s2) {
+                    return (s1 > s2);
+                }
+                i1++;
+                i2++;
+
+                c1 = block[i1 + 1];
+                c2 = block[i2 + 1];
+                if (c1 != c2) {
+                    return (c1 > c2);
+                }
+                s1 = quadrant[i1];
+                s2 = quadrant[i2];
+                if (s1 != s2) {
+                    return (s1 > s2);
+                }
+                i1++;
+                i2++;
+
+                if (i1 > last) {
+                    i1 -= last;
+                    i1--;
+                };
+                if (i2 > last) {
+                    i2 -= last;
+                    i2--;
+                };
+
+                k -= 4;
+                workDone++;
+            } while (k >= 0);
+
+            return false;
+        }
+
+        /*
+        Knuth's increments seem to work better
+        than Incerpi-Sedgewick here.  Possibly
+        because the number of elems to sort is
+        usually small, typically <= 20.
+        */
+        private int[] incs = { 1, 4, 13, 40, 121, 364, 1093, 3280,
+                            9841, 29524, 88573, 265720,
+                            797161, 2391484 };
+
+        private void AllocateCompressStructures() {
+            int n = BZip2Constants.baseBlockSize * blockSize100k;
+            block = new char[(n + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES)];
+            quadrant = new int[(n + BZip2Constants.NUM_OVERSHOOT_BYTES)];
+            zptr = new int[n];
+            ftab = new int[65537];
+
+            if (block == null || quadrant == null || zptr == null
+                || ftab == null) {
+                //int totalDraw = (n + 1 + NUM_OVERSHOOT_BYTES) + (n + NUM_OVERSHOOT_BYTES) + n + 65537;
+                //compressOutOfMemory ( totalDraw, n );
+            }
+
+            /*
+            The back end needs a place to store the MTF values
+            whilst it calculates the coding tables.  We could
+            put them in the zptr array.  However, these values
+            will fit in a short, so we overlay szptr at the
+            start of zptr, in the hope of reducing the number
+            of cache misses induced by the multiple traversals
+            of the MTF values when calculating coding tables.
+            Seems to improve compression speed by about 1%.
+            */
+            //    szptr = zptr;
+
+
+            szptr = new short[2 * n];
+        }
+
+        private void GenerateMTFValues() {
+            char[] yy = new char[256];
+            int  i, j;
+            char tmp;
+            char tmp2;
+            int zPend;
+            int wr;
+            int EOB;
+
+            MakeMaps();
+            EOB = nInUse + 1;
+
+            for (i = 0; i <= EOB; i++) {
+                mtfFreq[i] = 0;
+            }
+
+            wr = 0;
+            zPend = 0;
+            for (i = 0; i < nInUse; i++) {
+                yy[i] = (char) i;
+            }
+
+
+            for (i = 0; i <= last; i++) {
+                char ll_i;
+
+                ll_i = unseqToSeq[block[zptr[i]]];
+
+                j = 0;
+                tmp = yy[j];
+                while (ll_i != tmp) {
+                    j++;
+                    tmp2 = tmp;
+                    tmp = yy[j];
+                    yy[j] = tmp2;
+                };
+                yy[0] = tmp;
+
+                if (j == 0) {
+                    zPend++;
+                } else {
+                    if (zPend > 0) {
+                        zPend--;
+                        while (true) {
+                            switch (zPend % 2) {
+                            case 0:
+                                szptr[wr] = (short) BZip2Constants.RUNA;
+                                wr++;
+                                mtfFreq[BZip2Constants.RUNA]++;
+                                break;
+                            case 1:
+                                szptr[wr] = (short) BZip2Constants.RUNB;
+                                wr++;
+                                mtfFreq[BZip2Constants.RUNB]++;
+                                break;
+                            };
+                            if (zPend < 2) {
+                                break;
+                            }
+                            zPend = (zPend - 2) / 2;
+                        };
+                        zPend = 0;
+                    }
+                    szptr[wr] = (short) (j + 1);
+                    wr++;
+                    mtfFreq[j + 1]++;
+                }
+            }
+
+            if (zPend > 0) {
+                zPend--;
+                while (true) {
+                    switch (zPend % 2) {
+                    case 0:
+                        szptr[wr] = (short) BZip2Constants.RUNA;
+                        wr++;
+                        mtfFreq[BZip2Constants.RUNA]++;
+                        break;
+                    case 1:
+                        szptr[wr] = (short) BZip2Constants.RUNB;
+                        wr++;
+                        mtfFreq[BZip2Constants.RUNB]++;
+                        break;
+                    }
+                    if (zPend < 2) {
+                        break;
+                    }
+                    zPend = (zPend - 2) / 2;
+                }
+            }
+
+            szptr[wr] = (short) EOB;
+            wr++;
+            mtfFreq[EOB]++;
+
+            nMTF = wr;
+        }
+
+        public override int Read(byte[] buffer, int offset, int count) {
+            return 0;
+        }
+    
+        public override long Seek(long offset, SeekOrigin origin) {
+            return 0;
+        }
+    
+        public override void SetLength(long value) {
+        }
+    
+        public override void Write(byte[] buffer, int offset, int count) {
+            for (int k = 0; k < count; ++k) {
+                WriteByte(buffer[k + offset]);
+            }
+        }
+    
+        public override bool CanRead {
+            get {
+                return false;
+            }
+        }
+    
+        public override bool CanSeek {
+            get {
+                return false;
+            }
+        }
+    
+        public override bool CanWrite {
+            get {
+                return true;
+            }
+        }
+    
+        public override long Length {
+            get {
+                return 0;
+            }
+        }
+    
+        public override long Position {
+            get {
+                return 0;
+            }
+            set {
+            }
+        }
+    }
+}
\ No newline at end of file
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/crypto.csproj b/Crypto/crypto.csproj
new file mode 100644
index 000000000..9a541329d
--- /dev/null
+++ b/Crypto/crypto.csproj
@@ -0,0 +1,3469 @@
+<?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>Profile136</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
diff --git a/Crypto/doc/crypto.xml b/Crypto/doc/crypto.xml
new file mode 100644
index 000000000..f1cf2f391
--- /dev/null
+++ b/Crypto/doc/crypto.xml
@@ -0,0 +1,19296 @@
+<?xml version="1.0"?>
+<doc>
+    <assembly>
+        <name>crypto</name>
+    </assembly>
+    <members>
+        <member name="T:Org.BouncyCastle.Apache.Bzip2.BZip2Constants">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Apache.Bzip2.CBZip2InputStream">
+             An input stream that decompresses from the BZip2 format (with the file
+             header chars) to be read as any other stream.
+            
+             @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+            
+             <b>NB:</b> note this class has been modified to read the leading BZ from the
+             start of the BZIP2 stream to make it compatible with other PGP programs.
+        </member>
+        <member name="T:Org.BouncyCastle.Apache.Bzip2.CBZip2OutputStream">
+             An output stream that compresses into the BZip2 format (with the file
+             header chars) into another stream.
+            
+             @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+            
+             TODO:    Update to BZip2 1.0.1
+             <b>NB:</b> note this class has been modified to add a leading BZ to the
+             start of the BZIP2 stream to make it compatible with other PGP programs.
+        </member>
+        <member name="M:Org.BouncyCastle.Apache.Bzip2.CBZip2OutputStream.WriteByte(System.Byte)">
+            
+             modified by Oliver Merkel, 010128
+            
+        </member>
+        <member name="T:Org.BouncyCastle.Apache.Bzip2.CRC">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Encodable.GetDerEncoded">
+             Return the DER encoding of the object, null if the DER encoding can not be made.
+            
+             @return a DER byte array, null otherwise.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Asn1InputStream">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1InputStream.#ctor(System.IO.Stream,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1InputStream.#ctor(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1InputStream.BuildObject(System.Int32,System.Int32,System.Int32)">
+            build an object given its tag and the number of bytes to construct it from.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Asn1Null">
+            A Null object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Object.FromByteArray(System.Byte[])">
+            <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="T:System.IO.IOException">If there is a problem parsing the data.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Object.FromStream(System.IO.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="T:System.IO.IOException">If there is a problem parsing the data.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1OctetString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1OctetString.GetInstance(System.Object)">
+             return an Octet string from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1OctetString.#ctor(System.Byte[])">
+            @param string the octets making up the octet string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Sequence.GetInstance(System.Object)">
+             return an Asn1Sequence from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Sequence.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             Return an ASN1 sequence from a tagged object. There is a special
+             case here, if an object appears to have been explicitly tagged on
+             reading but we were expecting it to be implicitly tagged in the
+             normal course of events it indicates that we lost the surrounding
+             sequence - so we need to add it back (this will happen if the tagged
+             object is a sequence that contains other sequences). If you are
+             dealing with implicitly tagged sequences you really <b>should</b>
+             be using this method.
+            
+             @param obj the tagged object.
+             @param explicitly true if the object is meant to be explicitly tagged,
+                      false otherwise.
+             @exception ArgumentException if the tagged object cannot
+                      be converted.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Asn1Sequence.Item(System.Int32)">
+             return the object at the sequence position indicated by index.
+            
+             @param index the sequence number (starting at zero) of the object
+             @return the object at the sequence position indicated by index.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Set.GetInstance(System.Object)">
+             return an ASN1Set from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Set.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             Return an ASN1 set from a tagged object. There is a special
+             case here, if an object appears to have been explicitly tagged on
+             reading but we were expecting it to be implicitly tagged in the
+             normal course of events it indicates that we lost the surrounding
+             set - so we need to add it back (this will happen if the tagged
+             object is a sequence that contains other sequences). If you are
+             dealing with implicitly tagged sets you really <b>should</b>
+             be using this method.
+            
+             @param obj the tagged object.
+             @param explicitly true if the object is meant to be explicitly tagged
+                      false otherwise.
+             @exception ArgumentException if the tagged object cannot
+                      be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Set.LessThanOrEqual(System.Byte[],System.Byte[])">
+            return true if a &lt;= b (arrays are assumed padded with zeros).
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Asn1Set.Item(System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Asn1TaggedObject">
+            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).
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1TaggedObject.#ctor(System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param tagNo the tag number for this object.
+            @param obj the tagged object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1TaggedObject.#ctor(System.Boolean,System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param explicitly true if the object is explicitly tagged.
+            @param tagNo the tag number for this object.
+            @param obj the tagged object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1TaggedObject.IsExplicit">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1TaggedObject.GetObject">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1TaggedObject.GetObjectParser(System.Int32,System.Boolean)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerApplicationSpecific">
+            Base class for an application specific object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerApplicationSpecific.GetObject">
+             Return the enclosed object assuming explicit tagging.
+            
+             @return  the resulting object
+             @throws IOException if reconstruction fails.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerApplicationSpecific.GetObject(System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.BerNull">
+            A BER Null object.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerNull">
+            A Null object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerOctetString.#ctor(System.Byte[])">
+            <param name="str">The octets making up the octet string.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerOctetString.ToBytes(System.Collections.IEnumerable)">
+            convert a vector of octet strings into a single byte string
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerOctetString.#ctor(System.Byte[])">
+            <param name="str">The octets making up the octet string.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerOctetString.GetEnumerator">
+            return the DER octets that make up this string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerSequence.#ctor">
+            create an empty sequence
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerSequence.#ctor(Org.BouncyCastle.Asn1.Asn1Encodable)">
+            create a sequence containing one object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerSequence.#ctor(Org.BouncyCastle.Asn1.Asn1EncodableVector)">
+            create a sequence containing a vector of objects.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerSequence.#ctor">
+            create an empty sequence
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerSequence.#ctor(Org.BouncyCastle.Asn1.Asn1Encodable)">
+            create a sequence containing one object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerSequence.#ctor(Org.BouncyCastle.Asn1.Asn1EncodableVector)">
+            create a sequence containing a vector of objects.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerSet">
+            A Der encoded set object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerSet.#ctor">
+            create an empty set
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerSet.#ctor(Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param obj - a single object that makes up the set.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerSet.#ctor(Org.BouncyCastle.Asn1.Asn1EncodableVector)">
+            @param v - a vector of objects making up the set.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerSet.#ctor">
+            create an empty sequence
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerSet.#ctor(Org.BouncyCastle.Asn1.Asn1Encodable)">
+            create a set containing one object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerSet.#ctor(Org.BouncyCastle.Asn1.Asn1EncodableVector)">
+            create a set containing a vector of objects.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.BerTaggedObject">
+            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).
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerTaggedObject">
+            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).
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerTaggedObject.#ctor(System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param tagNo the tag number for this object.
+            @param obj the tagged object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerTaggedObject.#ctor(System.Boolean,System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param explicitly true if an explicitly tagged object.
+            @param tagNo the tag number for this object.
+            @param obj the tagged object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerTaggedObject.#ctor(System.Int32)">
+            create an implicitly tagged object that contains a zero
+            length sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerTaggedObject.#ctor(System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param tagNo the tag number for this object.
+            @param obj the tagged object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerTaggedObject.#ctor(System.Boolean,System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param explicitly true if an explicitly tagged object.
+            @param tagNo the tag number for this object.
+            @param obj the tagged object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerTaggedObject.#ctor(System.Int32)">
+            create an implicitly tagged object that contains a zero
+            length sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CAKeyUpdAnnContent.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CertConfirmContent.ToAsn1Object">
+            <pre>
+            CertConfirmContent ::= SEQUENCE OF CertStatus
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CertifiedKeyPair.ToAsn1Object">
+            <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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IAsn1Choice">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CertOrEncCert.ToAsn1Object">
+            <pre>
+            CertOrEncCert ::= CHOICE {
+                                 certificate     [0] CMPCertificate,
+                                 encryptedCert   [1] EncryptedValue
+                      }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CertRepMessage.ToAsn1Object">
+            <pre>
+            CertRepMessage ::= SEQUENCE {
+                                     caPubs       [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate
+                                                                                        OPTIONAL,
+                                     response         SEQUENCE OF CertResponse
+            }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CertResponse.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CertStatus.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.Challenge.ToAsn1Object">
+             <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CmpCertificate.#ctor(Org.BouncyCastle.Asn1.X509.AttributeCertificate)">
+            Note: the addition of attribute certificates is a BC extension.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CmpCertificate.ToAsn1Object">
+             <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CrlAnnContent.ToAsn1Object">
+            <pre>
+            CrlAnnContent ::= SEQUENCE OF CertificateList
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.ErrorMsgContent.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.GenMsgContent.ToAsn1Object">
+            <pre>
+            GenMsgContent ::= SEQUENCE OF InfoTypeAndValue
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.GenRepContent.ToAsn1Object">
+            <pre>
+            GenRepContent ::= SEQUENCE OF InfoTypeAndValue
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cmp.InfoTypeAndValue">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.InfoTypeAndValue.ToAsn1Object">
+            <pre>
+            InfoTypeAndValue ::= SEQUENCE {
+                                    infoType               OBJECT IDENTIFIER,
+                                    infoValue              ANY DEFINED BY infoType  OPTIONAL
+            }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.KeyRecRepContent.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.OobCertHash.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PbmParameter.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiBody.#ctor(System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            Creates a new PkiBody.
+            @param type one of the TYPE_* constants
+            @param content message content
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiBody.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiConfirmContent.ToAsn1Object">
+            <pre>
+            PkiConfirmContent ::= NULL
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cmp.PkiFailureInfo">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IAsn1String">
+            basic interface for Der string objects.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBitString.GetPadBits(System.Int32)">
+            return the correct number of pad bits for a bit string defined in
+            a 32 bit constant
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBitString.GetBytes(System.Int32)">
+            return the correct number of bytes for a bit string defined in
+            a 32 bit constant
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBitString.GetInstance(System.Object)">
+             return a Bit string from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBitString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBitString.#ctor(System.Byte[],System.Int32)">
+            @param data the octets making up the bit string.
+            @param padBits the number of extra bits at the end of the string.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.DerBitString.IntValue">
+            @return the value of the bit string as an int (truncating if necessary)
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiFailureInfo.#ctor(System.Int32)">
+            Basic constructor.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiFreeText.ToAsn1Object">
+            <pre>
+            PkiFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
+            </pre>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Cmp.PkiFreeText.Size">
+             Return the number of string elements present.
+            
+             @return number of elements present.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Cmp.PkiFreeText.Item(System.Int32)">
+             Return the UTF8STRING at index.
+            
+             @param index index of the string of interest
+             @return the string at index.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.Cmp.PkiHeader.NULL_NAME">
+            Value for a "null" recipient or sender.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiHeader.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiHeaderBuilder.Build">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiMessage.#ctor(Org.BouncyCastle.Asn1.Cmp.PkiHeader,Org.BouncyCastle.Asn1.Cmp.PkiBody,Org.BouncyCastle.Asn1.DerBitString,Org.BouncyCastle.Asn1.Cmp.CmpCertificate[])">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiMessage.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiMessages.ToAsn1Object">
+            <pre>
+            PkiMessages ::= SEQUENCE SIZE (1..MAX) OF PkiMessage
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiStatusInfo.#ctor(System.Int32)">
+            @param status
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiStatusInfo.#ctor(System.Int32,Org.BouncyCastle.Asn1.Cmp.PkiFreeText)">
+            @param status
+            @param statusString
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiStatusInfo.ToAsn1Object">
+             <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PollRepContent.ToAsn1Object">
+            <pre>
+            PollRepContent ::= SEQUENCE OF SEQUENCE {
+                    certReqId              INTEGER,
+                    checkAfter             INTEGER,  -- time in seconds
+                    reason                 PKIFreeText OPTIONAL
+                }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PollReqContent.ToAsn1Object">
+            <pre>
+            PollReqContent ::= SEQUENCE OF SEQUENCE {
+                                   certReqId              INTEGER
+            }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PopoDecKeyChallContent.ToAsn1Object">
+            <pre>
+            PopoDecKeyChallContent ::= SEQUENCE OF Challenge
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PopoDecKeyRespContent.ToAsn1Object">
+            <pre>
+            PopoDecKeyRespContent ::= SEQUENCE OF INTEGER
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.ProtectedPart.ToAsn1Object">
+            <pre>
+            ProtectedPart ::= SEQUENCE {
+                               header    PKIHeader,
+                               body      PKIBody
+            }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.RevAnnContent.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.RevDetails.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.RevRepContent.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.RevReqContent.ToAsn1Object">
+            <pre>
+            RevReqContent ::= SEQUENCE OF RevDetails
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Attribute.GetInstance(System.Object)">
+             return an Attribute object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Attribute.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Attribute ::= SEQUENCE {
+                attrType OBJECT IDENTIFIER,
+                attrValues SET OF AttributeValue
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Attributes.ToAsn1Object">
+            <pre>
+            Attributes ::=
+              SET SIZE(1..MAX) OF Attribute -- according to RFC 5652
+            </pre>
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AttributeTable.GetAll(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be
+             empty if there are no attributes of the required type present.
+            
+             @param oid type of attribute required.
+             @return a vector of all the attributes found of type oid.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AttributeTable.Add(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.Asn1Encodable)">
+             Return a new table with the passed in attribute added.
+            
+             @param attrType
+             @param attrValue
+             @return
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Cms.AttributeTable.Item(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            <summary>Return the first attribute matching the given OBJECT IDENTIFIER</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AuthenticatedData.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AuthenticatedData.GetInstance(System.Object)">
+             return an AuthenticatedData object from the given object.
+            
+             @param obj the object we want converted.
+             @throws ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AuthenticatedData.ToAsn1Object">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.AuthenticatedDataParser">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AuthEnvelopedData.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AuthEnvelopedData.GetInstance(System.Object)">
+             return an AuthEnvelopedData object from the given object.
+            
+             @param obj the object we want converted.
+             @throws ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AuthEnvelopedData.ToAsn1Object">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.AuthEnvelopedDataParser">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.CompressedData">
+            RFC 3274 - CMS Compressed Data.
+            <pre>
+            CompressedData ::= Sequence {
+             version CMSVersion,
+             compressionAlgorithm CompressionAlgorithmIdentifier,
+             encapContentInfo EncapsulatedContentInfo
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.CompressedData.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.CompressedData.GetInstance(System.Object)">
+             return a CompressedData object from the given object.
+            
+             @param _obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.CompressedDataParser">
+            RFC 3274 - CMS Compressed Data.
+            <pre>
+            CompressedData ::= SEQUENCE {
+             version CMSVersion,
+             compressionAlgorithm CompressionAlgorithmIdentifier,
+             encapContentInfo EncapsulatedContentInfo
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.ContentInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            ContentInfo ::= Sequence {
+                     contentType ContentType,
+                     content
+                     [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.ContentInfoParser">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            ContentInfo ::= SEQUENCE {
+                     contentType ContentType,
+                     content
+                     [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Ecc.MQVuserKeyingMaterial.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Ecc.MQVuserKeyingMaterial.GetInstance(System.Object)">
+             return an AuthEnvelopedData object from the given object.
+            
+             @param obj the object we want converted.
+             @throws ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Ecc.MQVuserKeyingMaterial.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            MQVuserKeyingMaterial ::= SEQUENCE {
+              ephemeralPublicKey OriginatorPublicKey,
+              addedukm [0] EXPLICIT UserKeyingMaterial OPTIONAL  }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.EncryptedContentInfo.GetInstance(System.Object)">
+             return an EncryptedContentInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.EncryptedContentInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            EncryptedContentInfo ::= Sequence {
+                contentType ContentType,
+                contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+                encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.EncryptedContentInfoParser">
+            <pre>
+            EncryptedContentInfo ::= SEQUENCE {
+                contentType ContentType,
+                contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+                encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.EncryptedData.ToAsn1Object">
+            <pre>
+                  EncryptedData ::= SEQUENCE {
+                                version CMSVersion,
+                                encryptedContentInfo EncryptedContentInfo,
+                                unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.EnvelopedData.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             return an EnvelopedData 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.EnvelopedData.GetInstance(System.Object)">
+             return an EnvelopedData object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.EnvelopedData.ToAsn1Object">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.EnvelopedDataParser">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KekIdentifier.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KekIdentifier.GetInstance(System.Object)">
+             return a KekIdentifier object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KekIdentifier.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            KekIdentifier ::= Sequence {
+                keyIdentifier OCTET STRING,
+                date GeneralizedTime OPTIONAL,
+                other OtherKeyAttribute OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KekRecipientInfo.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KekRecipientInfo.GetInstance(System.Object)">
+             return a KekRecipientInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KekRecipientInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            KekRecipientInfo ::= Sequence {
+                version CMSVersion,  -- always set to 4
+                kekID KekIdentifier,
+                keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+                encryptedKey EncryptedKey
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyAgreeRecipientIdentifier.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyAgreeRecipientIdentifier.GetInstance(System.Object)">
+             return an KeyAgreeRecipientIdentifier object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyAgreeRecipientIdentifier.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            KeyAgreeRecipientIdentifier ::= CHOICE {
+                issuerAndSerialNumber IssuerAndSerialNumber,
+                rKeyId [0] IMPLICIT RecipientKeyIdentifier
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyAgreeRecipientInfo.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyAgreeRecipientInfo.GetInstance(System.Object)">
+             return a KeyAgreeRecipientInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyAgreeRecipientInfo.ToAsn1Object">
+                     * 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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyTransRecipientInfo.GetInstance(System.Object)">
+             return a KeyTransRecipientInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyTransRecipientInfo.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.MetaData.ToAsn1Object">
+            <pre>
+            MetaData ::= SEQUENCE {
+              hashProtected        BOOLEAN,
+              fileName             UTF8String OPTIONAL,
+              mediaType            IA5String OPTIONAL,
+              otherMetaData        Attributes OPTIONAL
+            }
+            </pre>
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorIdentifierOrKey.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorIdentifierOrKey.GetInstance(System.Object)">
+             return an OriginatorIdentifierOrKey object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorIdentifierOrKey.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <pre>
+             OriginatorIdentifierOrKey ::= CHOICE {
+                 issuerAndSerialNumber IssuerAndSerialNumber,
+                 subjectKeyIdentifier [0] SubjectKeyIdentifier,
+                 originatorKey [1] OriginatorPublicKey
+             }
+            
+             SubjectKeyIdentifier ::= OCTET STRING
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorInfo.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorInfo.GetInstance(System.Object)">
+             return an OriginatorInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            OriginatorInfo ::= Sequence {
+                certs [0] IMPLICIT CertificateSet OPTIONAL,
+                crls [1] IMPLICIT CertificateRevocationLists OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorPublicKey.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorPublicKey.GetInstance(System.Object)">
+             return an OriginatorPublicKey object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorPublicKey.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            OriginatorPublicKey ::= Sequence {
+                algorithm AlgorithmIdentifier,
+                publicKey BIT STRING
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OtherKeyAttribute.GetInstance(System.Object)">
+             return an OtherKeyAttribute object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OtherKeyAttribute.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            OtherKeyAttribute ::= Sequence {
+                keyAttrId OBJECT IDENTIFIER,
+                keyAttr ANY DEFINED BY keyAttrId OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OtherRecipientInfo.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             return a OtherRecipientInfo 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OtherRecipientInfo.GetInstance(System.Object)">
+             return a OtherRecipientInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OtherRecipientInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            OtherRecipientInfo ::= Sequence {
+               oriType OBJECT IDENTIFIER,
+               oriValue ANY DEFINED BY oriType }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.PasswordRecipientInfo.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.PasswordRecipientInfo.GetInstance(System.Object)">
+             return a PasswordRecipientInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.PasswordRecipientInfo.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientEncryptedKey.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientEncryptedKey.GetInstance(System.Object)">
+             return a RecipientEncryptedKey object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientEncryptedKey.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            RecipientEncryptedKey ::= SEQUENCE {
+                rid KeyAgreeRecipientIdentifier,
+                encryptedKey EncryptedKey
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientIdentifier.GetInstance(System.Object)">
+             return a RecipientIdentifier object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientIdentifier.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <pre>
+             RecipientIdentifier ::= CHOICE {
+                 issuerAndSerialNumber IssuerAndSerialNumber,
+                 subjectKeyIdentifier [0] SubjectKeyIdentifier
+             }
+            
+             SubjectKeyIdentifier ::= OCTET STRING
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientInfo.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientKeyIdentifier.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientKeyIdentifier.GetInstance(System.Object)">
+             return a RecipientKeyIdentifier object from the given object.
+            
+             @param _obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientKeyIdentifier.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <pre>
+             RecipientKeyIdentifier ::= Sequence {
+                 subjectKeyIdentifier SubjectKeyIdentifier,
+                 date GeneralizedTime OPTIONAL,
+                 other OtherKeyAttribute OPTIONAL
+             }
+            
+             SubjectKeyIdentifier ::= OCTET STRING
+             </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.SignedData">
+            a signed data object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.SignedData.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            SignedData ::= Sequence {
+                version CMSVersion,
+                digestAlgorithms DigestAlgorithmIdentifiers,
+                encapContentInfo EncapsulatedContentInfo,
+                certificates [0] IMPLICIT CertificateSet OPTIONAL,
+                crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+                signerInfos SignerInfos
+              }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.SignedDataParser">
+            <pre>
+            SignedData ::= SEQUENCE {
+                version CMSVersion,
+                digestAlgorithms DigestAlgorithmIdentifiers,
+                encapContentInfo EncapsulatedContentInfo,
+                certificates [0] IMPLICIT CertificateSet OPTIONAL,
+                crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+                signerInfos SignerInfos
+              }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.SignerIdentifier.GetInstance(System.Object)">
+             return a SignerIdentifier object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.SignerIdentifier.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <pre>
+             SignerIdentifier ::= CHOICE {
+                 issuerAndSerialNumber IssuerAndSerialNumber,
+                 subjectKeyIdentifier [0] SubjectKeyIdentifier
+             }
+            
+             SubjectKeyIdentifier ::= OCTET STRING
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.SignerInfo.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <pre>
+              SignerInfo ::= Sequence {
+                  version Version,
+                  SignerIdentifier sid,
+                  digestAlgorithm DigestAlgorithmIdentifier,
+                  authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
+                  digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+                  encryptedDigest EncryptedDigest,
+                  unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+              }
+            
+              EncryptedDigest ::= OCTET STRING
+            
+              DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+            
+              DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Time.#ctor(System.DateTime)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Time.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Time ::= CHOICE {
+                        utcTime        UTCTime,
+                        generalTime    GeneralizedTime }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.TimeStampAndCrl.ToAsn1Object">
+            <pre>
+            TimeStampAndCRL ::= SEQUENCE {
+                timeStamp   TimeStampToken,          -- according to RFC 3161
+                crl         CertificateList OPTIONAL -- according to RFC 5280
+             }
+            </pre>
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.TimeStampedData.ToAsn1Object">
+            <pre>
+            TimeStampedData ::= SEQUENCE {
+              version              INTEGER { v1(1) },
+              dataUri              IA5String OPTIONAL,
+              metaData             MetaData OPTIONAL,
+              content              OCTET STRING OPTIONAL,
+              temporalEvidence     Evidence
+            }
+            </pre>
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.TimeStampTokenEvidence.ToAsn1Object">
+            <pre>
+            TimeStampTokenEvidence ::=
+               SEQUENCE SIZE(1..MAX) OF TimeStampAndCrl
+            </pre>
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.AttributeTypeAndValue.ToAsn1Object">
+            <pre>
+            AttributeTypeAndValue ::= SEQUENCE {
+                      type         OBJECT IDENTIFIER,
+                      value        ANY DEFINED BY type }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertId.ToAsn1Object">
+            <pre>
+            CertId ::= SEQUENCE {
+                            issuer           GeneralName,
+                            serialNumber     INTEGER }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertReqMessages.ToAsn1Object">
+            <pre>
+            CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertReqMsg.#ctor(Org.BouncyCastle.Asn1.Crmf.CertRequest,Org.BouncyCastle.Asn1.Crmf.ProofOfPossession,Org.BouncyCastle.Asn1.Crmf.AttributeTypeAndValue[])">
+            Creates a new CertReqMsg.
+            @param certReq CertRequest
+            @param popo may be null
+            @param regInfo may be null
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertReqMsg.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertRequest.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertTemplate.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertTemplateBuilder.SetVersion(System.Int32)">
+            Sets the X.509 version. Note: for X509v3, use 2 here. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertTemplateBuilder.SetIssuerUID(Org.BouncyCastle.Asn1.DerBitString)">
+            Sets the issuer unique ID (deprecated in X.509v3) 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertTemplateBuilder.SetSubjectUID(Org.BouncyCastle.Asn1.DerBitString)">
+            Sets the subject unique ID (deprecated in X.509v3) 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertTemplateBuilder.Build">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.Controls.ToAsn1Object">
+            <pre>
+            Controls  ::= SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.EncKeyWithID.ToAsn1Object">
+            <pre>
+            EncKeyWithID ::= SEQUENCE {
+                 privateKey           PrivateKeyInfo,
+                 identifier CHOICE {
+                    string               UTF8String,
+                    generalName          GeneralName
+                } OPTIONAL
+            }
+            </pre>
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.EncryptedKey.ToAsn1Object">
+            <pre>
+               EncryptedKey ::= CHOICE {
+                   encryptedValue        EncryptedValue, -- deprecated
+                   envelopedData     [0] EnvelopedData }
+                   -- The encrypted private key MUST be placed in the envelopedData
+                   -- encryptedContentInfo encryptedContent OCTET STRING.
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.EncryptedValue.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.OptionalValidity.ToAsn1Object">
+            <pre>
+            OptionalValidity ::= SEQUENCE {
+                                   notBefore  [0] Time OPTIONAL,
+                                   notAfter   [1] Time OPTIONAL } --at least one MUST be present
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PkiArchiveOptions.ToAsn1Object">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PkiPublicationInfo.ToAsn1Object">
+            <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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Crmf.PKMacValue">
+            Password-based MAC value for use with POPOSigningKeyInput.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PKMacValue.#ctor(Org.BouncyCastle.Asn1.Cmp.PbmParameter,Org.BouncyCastle.Asn1.DerBitString)">
+            Creates a new PKMACValue.
+            @param params parameters for password-based MAC
+            @param value MAC of the DER-encoded SubjectPublicKeyInfo
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PKMacValue.#ctor(Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier,Org.BouncyCastle.Asn1.DerBitString)">
+            Creates a new PKMACValue.
+            @param aid CMPObjectIdentifiers.passwordBasedMAC, with PBMParameter
+            @param value MAC of the DER-encoded SubjectPublicKeyInfo
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PKMacValue.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PopoPrivKey.ToAsn1Object">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PopoSigningKey.#ctor(Org.BouncyCastle.Asn1.Crmf.PopoSigningKeyInput,Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier,Org.BouncyCastle.Asn1.DerBitString)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PopoSigningKey.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PopoSigningKeyInput.#ctor(Org.BouncyCastle.Asn1.X509.GeneralName,Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo)">
+            Creates a new PopoSigningKeyInput with sender name as authInfo. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PopoSigningKeyInput.#ctor(Org.BouncyCastle.Asn1.Crmf.PKMacValue,Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo)">
+            Creates a new PopoSigningKeyInput using password-based MAC. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PopoSigningKeyInput.ToAsn1Object">
+            <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.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Crmf.PopoSigningKeyInput.Sender">
+            Returns the sender field, or null if authInfo is publicKeyMac 
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Crmf.PopoSigningKeyInput.PublicKeyMac">
+            Returns the publicKeyMac field, or null if authInfo is sender 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.#ctor">
+            Creates a ProofOfPossession with type raVerified. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.#ctor(Org.BouncyCastle.Asn1.Crmf.PopoSigningKey)">
+            Creates a ProofOfPossession for a signing key. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.#ctor(System.Int32,Org.BouncyCastle.Asn1.Crmf.PopoPrivKey)">
+            Creates a ProofOfPossession for key encipherment or agreement.
+            @param type one of TYPE_KEY_ENCIPHERMENT or TYPE_KEY_AGREEMENT
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.SinglePubInfo.ToAsn1Object">
+            <pre>
+            SinglePubInfo ::= SEQUENCE {
+                   pubMethod    INTEGER {
+                      dontCare    (0),
+                      x500        (1),
+                      web         (2),
+                      ldap        (3) },
+                  pubLocation  GeneralName OPTIONAL }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerInteger.GetInstance(System.Object)">
+             return an integer from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerInteger.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.DerInteger.PositiveValue">
+            in some cases positive values Get crammed into a space,
+            that's not quite big enough...
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.CryptoPro.ECGost3410NamedCurves">
+            table of the available named parameters for GOST 3410-2001.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.CryptoPro.ECGost3410NamedCurves.GetByOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             return the ECDomainParameters object for the given OID, null if it
+             isn't present.
+            
+             @param oid an object identifier representing a named parameters, if present.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.CryptoPro.ECGost3410NamedCurves.GetName(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            return the named curve name represented by the given object identifier.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.CryptoPro.ECGost3410NamedCurves.Names">
+            returns an enumeration containing the name strings for curves
+            contained in this structure.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.CryptoPro.Gost28147Parameters.ToAsn1Object">
+             <pre>
+             Gost28147-89-Parameters ::=
+                           SEQUENCE {
+                                   iv                   Gost28147-89-IV,
+                                   encryptionParamSet   OBJECT IDENTIFIER
+                            }
+            
+               Gost28147-89-IV ::= OCTET STRING (SIZE (8))
+             </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.CryptoPro.Gost3410NamedParameters">
+            table of the available named parameters for GOST 3410-94.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.CryptoPro.Gost3410NamedParameters.GetByOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.CryptoPro.Gost3410NamedParameters.Names">
+            returns an enumeration containing the name strings for parameters
+            contained in this structure.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerBmpString">
+            Der BMPString object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBmpString.GetInstance(System.Object)">
+             return a BMP string from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBmpString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBmpString.#ctor(System.Byte[])">
+            basic constructor - byte encoded string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBmpString.#ctor(System.String)">
+            basic constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBoolean.GetInstance(System.Object)">
+             return a bool from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBoolean.GetInstance(System.Boolean)">
+            return a DerBoolean from the passed in bool.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBoolean.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             return a Boolean 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerEnumerated.GetInstance(System.Object)">
+             return an integer from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerEnumerated.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             return an Enumerated 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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerExternal">
+            Class representing the DER-type External
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerExternal.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.DerInteger,Org.BouncyCastle.Asn1.Asn1Object,Org.BouncyCastle.Asn1.DerTaggedObject)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerExternal.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.DerInteger,Org.BouncyCastle.Asn1.Asn1Object,System.Int32,Org.BouncyCastle.Asn1.Asn1Object)">
+            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
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.DerExternal.Encoding">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerGeneralizedTime">
+            Generalized time object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerGeneralizedTime.GetInstance(System.Object)">
+             return a generalized time from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerGeneralizedTime.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             return a Generalized Time 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 tagged object cannot
+                           be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerGeneralizedTime.#ctor(System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerGeneralizedTime.#ctor(System.DateTime)">
+            base constructor from a local time object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerGeneralizedTime.GetTime">
+            return the time - always in the form of
+             YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+            <p>
+            Normally in a certificate we would expect "Z" rather than "GMT",
+            however adding the "GMT" means we can just use:
+            <pre>
+                dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+            </pre>
+            To read in the time and Get a date which is compatible with our local
+            time zone.</p>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.DerGeneralizedTime.TimeString">
+            Return the time.
+            @return The time string as it appeared in the encoded object.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerIA5String">
+            Der IA5String object - this is an ascii string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerIA5String.GetInstance(System.Object)">
+             return a IA5 string from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerIA5String.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerIA5String.#ctor(System.Byte[])">
+            basic constructor - with bytes.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerIA5String.#ctor(System.String)">
+            basic constructor - without validation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerIA5String.#ctor(System.String,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerIA5String.IsIA5String(System.String)">
+             return true if the passed in String can be represented without
+             loss as an IA5String, false otherwise.
+            
+             @return true if in printable set, false otherwise.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerNumericString">
+            Der NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerNumericString.GetInstance(System.Object)">
+             return a Numeric string from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerNumericString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerNumericString.#ctor(System.Byte[])">
+            basic constructor - with bytes.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerNumericString.#ctor(System.String)">
+            basic constructor -  without validation..
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerNumericString.#ctor(System.String,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerNumericString.IsNumericString(System.String)">
+             Return true if the string can be represented as a NumericString ('0'..'9', ' ')
+            
+             @param str string to validate.
+             @return true if numeric, fale otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerObjectIdentifier.GetInstance(System.Object)">
+             return an Oid from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerObjectIdentifier.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             return an object Identifier 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerObjectIdentifier.On(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            Return  true if this oid is an extension of the passed in branch, stem.
+            @param stem the arc or branch that is a possible parent.
+            @return  true if the branch is on the passed in stem, false otherwise.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerPrintableString">
+            Der PrintableString object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerPrintableString.GetInstance(System.Object)">
+             return a printable string from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerPrintableString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerPrintableString.#ctor(System.Byte[])">
+            basic constructor - byte encoded string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerPrintableString.#ctor(System.String)">
+            basic constructor - this does not validate the string
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerPrintableString.#ctor(System.String,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerPrintableString.IsPrintableString(System.String)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerT61String">
+            Der T61String (also the teletex string) - 8-bit characters
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerT61String.GetInstance(System.Object)">
+             return a T61 string from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerT61String.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerT61String.#ctor(System.Byte[])">
+            basic constructor - with bytes.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerT61String.#ctor(System.String)">
+            basic constructor - with string.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerUniversalString">
+            Der UniversalString object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUniversalString.GetInstance(System.Object)">
+             return a Universal string from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUniversalString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUniversalString.#ctor(System.Byte[])">
+            basic constructor - byte encoded string.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerUnknownTag">
+            We insert one of these when we find a tag we don't recognise.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUnknownTag.#ctor(System.Int32,System.Byte[])">
+            @param tag the tag value.
+            @param data the contents octets.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerUtcTime">
+            UTC time object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtcTime.GetInstance(System.Object)">
+             return an UTC Time from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtcTime.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtcTime.#ctor(System.String)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtcTime.#ctor(System.DateTime)">
+            base constructor from a DateTime object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtcTime.ToDateTime">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtcTime.ToAdjustedDateTime">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.DerUtcTime.TimeString">
+            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>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.DerUtcTime.AdjustedTimeString">
+            <summary>
+            Return a time string as an adjusted date with a 4 digit year.
+            This goes in the range of 1950 - 2049.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerUtf8String">
+            Der UTF8String object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtf8String.GetInstance(System.Object)">
+             return an UTF8 string from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtf8String.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtf8String.#ctor(System.Byte[])">
+            basic constructor - byte encoded string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtf8String.#ctor(System.String)">
+            basic constructor
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerVisibleString">
+            Der VisibleString object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerVisibleString.GetInstance(System.Object)">
+             return a Visible string from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerVisibleString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerVisibleString.#ctor(System.Byte[])">
+            basic constructor - byte encoded string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerVisibleString.#ctor(System.String)">
+            basic constructor
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CertificateValues">
+            <remarks>
+            RFC 3126: 4.3.1 Certificate Values Attribute Definition
+            <code>
+            CertificateValues ::= SEQUENCE OF Certificate
+            </code>
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.CommitmentTypeIndication.ToAsn1Object">
+            <pre>
+            CommitmentTypeIndication ::= SEQUENCE {
+                 commitmentTypeId   CommitmentTypeIdentifier,
+                 commitmentTypeQualifier   SEQUENCE SIZE (1..MAX) OF
+                         CommitmentTypeQualifier OPTIONAL }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CommitmentTypeQualifier">
+             Commitment type qualifiers, used in the Commitment-Type-Indication attribute (RFC3126).
+            
+             <pre>
+               CommitmentTypeQualifier ::= SEQUENCE {
+                   commitmentTypeIdentifier  CommitmentTypeIdentifier,
+                   qualifier          ANY DEFINED BY commitmentTypeIdentifier OPTIONAL }
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.CommitmentTypeQualifier.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             Creates a new <code>CommitmentTypeQualifier</code> instance.
+            
+             @param commitmentTypeIdentifier a <code>CommitmentTypeIdentifier</code> value
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.CommitmentTypeQualifier.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.Asn1Encodable)">
+             Creates a new <code>CommitmentTypeQualifier</code> instance.
+            
+             @param commitmentTypeIdentifier a <code>CommitmentTypeIdentifier</code> value
+             @param qualifier the qualifier, defined by the above field.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.CommitmentTypeQualifier.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Creates a new <code>CommitmentTypeQualifier</code> instance.
+            
+             @param as <code>CommitmentTypeQualifier</code> structure
+             encoded as an Asn1Sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.CommitmentTypeQualifier.ToAsn1Object">
+             Returns a DER-encodable representation of this instance.
+            
+             @return a <code>Asn1Object</code> value
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CompleteCertificateRefs">
+            <remarks>
+            RFC 3126: 4.2.1 Complete Certificate Refs Attribute Definition
+            <code>
+            CompleteCertificateRefs ::= SEQUENCE OF OtherCertID
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CompleteRevocationRefs">
+            <remarks>
+            RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+            <code>
+            CompleteRevocationRefs ::= SEQUENCE OF CrlOcspRef
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CrlIdentifier">
+            <remarks>
+            RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+            <code>
+            CrlIdentifier ::= SEQUENCE 
+            {
+            	crlissuer		Name,
+            	crlIssuedTime	UTCTime,
+            	crlNumber		INTEGER OPTIONAL
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CrlListID">
+            <remarks>
+            RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+            <code>
+            CRLListID ::= SEQUENCE 
+            {
+            	crls	SEQUENCE OF CrlValidatedID
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CrlOcspRef">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CrlValidatedID">
+            <remarks>
+            RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+            <code>
+            CrlValidatedID ::= SEQUENCE {
+            	crlHash			OtherHash,
+            	crlIdentifier	CrlIdentifier OPTIONAL}
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OcspIdentifier">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OcspListID">
+            <remarks>
+            RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+            <code>
+            OcspListID ::=  SEQUENCE {
+            	ocspResponses	SEQUENCE OF OcspResponsesID
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OcspResponsesID">
+            <remarks>
+            RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+            <code>
+            OcspResponsesID ::= SEQUENCE {
+            	ocspIdentifier	OcspIdentifier,
+            	ocspRepHash		OtherHash OPTIONAL
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OtherCertID">
+            <remarks>
+            <code>
+            OtherCertID ::= SEQUENCE {
+            	otherCertHash	OtherHash,
+            	issuerSerial	IssuerSerial OPTIONAL
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OtherHash">
+            <remarks>
+            <code>
+            OtherHash ::= CHOICE {
+            	sha1Hash	OtherHashValue, -- This contains a SHA-1 hash
+            	otherHash	OtherHashAlgAndValue
+            }
+            
+            OtherHashValue ::= OCTET STRING
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OtherHashAlgAndValue">
+            <summary>
+            Summary description for OtherHashAlgAndValue.
+            </summary>
+            <remarks>
+            <code>
+            OtherHashAlgAndValue ::= SEQUENCE {
+            	hashAlgorithm	AlgorithmIdentifier,
+            	hashValue		OtherHashValue
+            }
+            
+            OtherHashValue ::= OCTET STRING
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OtherRevRefs">
+             <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OtherRevVals">
+             <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OtherSigningCertificate">
+            <remarks>
+            <code>
+            OtherSigningCertificate ::= SEQUENCE {
+            	certs		SEQUENCE OF OtherCertID,
+            	policies	SEQUENCE OF PolicyInformation OPTIONAL
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.RevocationValues">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.SignaturePolicyId">
+            <remarks>
+            <code>
+            SignaturePolicyId ::= SEQUENCE {
+            	sigPolicyIdentifier		SigPolicyId,
+            	sigPolicyHash			SigPolicyHash,
+            	sigPolicyQualifiers		SEQUENCE SIZE (1..MAX) OF SigPolicyQualifierInfo OPTIONAL
+            }
+            
+            SigPolicyId ::= OBJECT IDENTIFIER
+            
+            SigPolicyHash ::= OtherHashAlgAndValue
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.SignaturePolicyIdentifier">
+            <remarks>
+            <code>
+            SignaturePolicyIdentifier ::= CHOICE {
+            	SignaturePolicyId		SignaturePolicyId,
+            	SignaturePolicyImplied	SignaturePolicyImplied
+            }
+            
+            SignaturePolicyImplied ::= NULL
+            </code>
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.SignerAttribute.ToAsn1Object">
+            
+             <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.SignerLocation">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.SignerLocation.ToAsn1Object">
+             <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.SigPolicyQualifierInfo">
+            <remarks>
+            <code>
+            SigPolicyQualifierInfo ::= SEQUENCE {
+            	sigPolicyQualifierId  SigPolicyQualifierId,
+            	sigQualifier          ANY DEFINED BY sigPolicyQualifierId
+            }
+            
+            SigPolicyQualifierId ::= OBJECT IDENTIFIER
+            </code>
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.ContentHints.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.ContentHints.ToAsn1Object">
+            <pre>
+            ContentHints ::= SEQUENCE {
+              contentDescription UTF8String (SIZE (1..MAX)) OPTIONAL,
+              contentType ContentType }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.ContentIdentifier.#ctor(Org.BouncyCastle.Asn1.Asn1OctetString)">
+            Create from OCTET STRING whose octets represent the identifier.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.ContentIdentifier.#ctor(System.Byte[])">
+            Create from byte array representing the identifier.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.ContentIdentifier.ToAsn1Object">
+            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 }
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.EssCertID.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.EssCertID.ToAsn1Object">
+            <pre>
+            EssCertID ::= SEQUENCE {
+                certHash Hash,
+                issuerSerial IssuerSerial OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.EssCertIDv2.ToAsn1Object">
+             <pre>
+             EssCertIDv2 ::=  SEQUENCE {
+                 hashAlgorithm     AlgorithmIdentifier
+                          DEFAULT {algorithm id-sha256},
+                 certHash          Hash,
+                 issuerSerial      IssuerSerial OPTIONAL
+             }
+            
+             Hash ::= OCTET STRING
+            
+             IssuerSerial ::= SEQUENCE {
+                 issuer         GeneralNames,
+                 serialNumber   CertificateSerialNumber
+             }
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.OtherCertID.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.OtherCertID.ToAsn1Object">
+             <pre>
+             OtherCertID ::= SEQUENCE {
+                 otherCertHash    OtherHash,
+                 issuerSerial     IssuerSerial OPTIONAL }
+            
+             OtherHash ::= CHOICE {
+                 sha1Hash     OCTET STRING,
+                 otherHash    OtherHashAlgAndValue }
+            
+             OtherHashAlgAndValue ::= SEQUENCE {
+                 hashAlgorithm    AlgorithmIdentifier,
+                 hashValue        OCTET STRING }
+            
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.OtherSigningCertificate.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            constructors
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.OtherSigningCertificate.ToAsn1Object">
+            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 }
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.SigningCertificate.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            constructors
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.SigningCertificate.ToAsn1Object">
+            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 }
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.SigningCertificateV2.ToAsn1Object">
+            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 }
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Icao.CscaMasterList">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Icao.DataGroupHash">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Icao.LdsSecurityObject">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Icao.LdsVersionInfo.ToAsn1Object">
+            <pre>
+            LDSVersionInfo ::= SEQUENCE {
+               ldsVersion PRINTABLE STRING
+               unicodeVersion PRINTABLE STRING
+             }
+            </pre>
+            @return
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttCPAccredited">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATDateOfCertGen">
+             Certificate extensionDate of certificate generation
+             
+             <pre>
+            		DateOfCertGenSyntax ::= GeneralizedTime
+             </pre>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATProcuration">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATAdmission">
+            Attribute to indicate admissions to certain professions. May be used as
+            attribute in attribute certificate or as extension in a certificate
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATMonetaryLimit">
+            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).
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATDeclarationOfMajority">
+            A declaration of majority. May be used as attribute in attribute
+            certificate or as extension in a certificate
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATIccsn">
+             
+             Serial number of the smart card containing the corresponding private key
+             
+             <pre>
+            		ICCSNSyntax ::= OCTET STRING (SIZE(8..20))
+             </pre>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATPKReference">
+             
+             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>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATRestriction">
+             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
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATRetrieveIfAllowed">
+             
+             (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>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATRequestedCertificate">
+            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
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATNamingAuthorities">
+            Base ObjectIdentifier for naming authorities
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATCertInDirSince">
+             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>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATCertHash">
+             Hash of a certificate in OCSP.
+            
+             @see Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATNameAtBirth">
+             <pre>
+            		NameAtBirth ::= DirectoryString(SIZE(1..64)
+             </pre>
+             
+             Used in
+             {@link Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes SubjectDirectoryAttributes}
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATAdditionalInformation">
+            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
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATLiabilityLimitationFlag">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash.#ctor(Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier,System.Byte[])">
+             Constructor from a given details.
+            
+             @param hashAlgorithm   The hash algorithm identifier.
+             @param certificateHash The hash of the whole DER encoding of the certificate.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <p/>
+             Returns:
+             <p/>
+             <pre>
+                 CertHash ::= SEQUENCE {
+                   hashAlgorithm AlgorithmIdentifier,
+                   certificateHash OCTET STRING
+                 }
+             </pre>
+            
+             @return an Asn1Object
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.RequestedCertificate">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.RequestedCertificate.#ctor(Org.BouncyCastle.Asn1.X509.X509CertificateStructure)">
+             Constructor from a given details.
+             <p/>
+             Only one parameter can be given. All other must be <code>null</code>.
+            
+             @param certificate Given as Certificate
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.RequestedCertificate.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.AdditionalInformationSyntax">
+            Some other information of non-restrictive nature regarding the usage of this
+            certificate.
+            
+            <pre>
+               AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.AdditionalInformationSyntax.#ctor(System.String)">
+             Constructor from a given details.
+            
+             @param information The describtion of the information.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.AdditionalInformationSyntax.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <p/>
+             Returns:
+             <p/>
+             <pre>
+               AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+             </pre>
+            
+             @return an Asn1Object
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.Admissions">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.Admissions.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.Admissions.#ctor(Org.BouncyCastle.Asn1.X509.GeneralName,Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority,Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.Admissions.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax">
+             Attribute to indicate admissions to certain professions.
+             <p/>
+             <pre>
+                 AdmissionSyntax ::= SEQUENCE
+                 {
+                   admissionAuthority GeneralName OPTIONAL,
+                   contentsOfAdmissions SEQUENCE OF Admissions
+                 }
+             <p/>
+                 Admissions ::= SEQUENCE
+                 {
+                   admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+                   namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+                   professionInfos SEQUENCE OF ProfessionInfo
+                 }
+             <p/>
+                 NamingAuthority ::= SEQUENCE
+                 {
+                   namingAuthorityId OBJECT IDENTIFIER OPTIONAL,
+                   namingAuthorityUrl IA5String OPTIONAL,
+                   namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+                 }
+             <p/>
+                 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>
+             <p/>
+             <p/>
+             ISIS-MTT PROFILE: The relatively complex structure of AdmissionSyntax
+             supports the following concepts and requirements:
+             <ul>
+             <li> External institutions (e.g. professional associations, chambers, unions,
+             administrative bodies, companies, etc.), which are responsible for granting
+             and verifying professional admissions, are indicated by means of the data
+             field admissionAuthority. An admission authority is indicated by a
+             GeneralName object. Here an X.501 directory name (distinguished name) can be
+             indicated in the field directoryName, a URL address can be indicated in the
+             field uniformResourceIdentifier, and an object identifier can be indicated in
+             the field registeredId.</li>
+             <li> The names of authorities which are responsible for the administration of
+             title registers are indicated in the data field namingAuthority. The name of
+             the authority can be identified by an object identifier in the field
+             namingAuthorityId, by means of a text string in the field
+             namingAuthorityText, by means of a URL address in the field
+             namingAuthorityUrl, or by a combination of them. For example, the text string
+             can contain the name of the authority, the country and the name of the title
+             register. The URL-option refers to a web page which contains lists with
+             �officially� registered professions (text and possibly OID) as well as
+             further information on these professions. Object identifiers for the
+             component namingAuthorityId are grouped under the OID-branch
+             id-isis-at-namingAuthorities and must be applied for.</li>
+             <li>See http://www.teletrust.de/anwend.asp?Id=30200&amp;Sprache=E_&amp;HomePG=0
+             for an application form and http://www.teletrust.de/links.asp?id=30220,11
+             for an overview of registered naming authorities.</li>
+             <li> By means of the data type ProfessionInfo certain professions,
+             specializations, disciplines, fields of activity, etc. are identified. A
+             profession is represented by one or more text strings, resp. profession OIDs
+             in the fields professionItems and professionOIDs and by a registration number
+             in the field registrationNumber. An indication in text form must always be
+             present, whereas the other indications are optional. The component
+             addProfessionInfo may contain additional applicationspecific information in
+             DER-encoded form.</li>
+             </ul>
+             <p/>
+             By means of different namingAuthority-OIDs or profession OIDs hierarchies of
+             professions, specializations, disciplines, fields of activity, etc. can be
+             expressed. The issuing admission authority should always be indicated (field
+             admissionAuthority), whenever a registration number is presented. Still,
+             information on admissions can be given without indicating an admission or a
+             naming authority by the exclusive use of the component professionItems. In
+             this case the certification authority is responsible for the verification of
+             the admission information.
+             <p/>
+             <p/>
+             <p/>
+             This attribute is single-valued. Still, several admissions can be captured in
+             the sequence structure of the component contentsOfAdmissions of
+             AdmissionSyntax or in the component professionInfos of Admissions. The
+             component admissionAuthority of AdmissionSyntax serves as default value for
+             the component admissionAuthority of Admissions. Within the latter component
+             the default value can be overwritten, in case that another authority is
+             responsible. The component namingAuthority of Admissions serves as a default
+             value for the component namingAuthority of ProfessionInfo. Within the latter
+             component the default value can be overwritten, in case that another naming
+             authority needs to be recorded.
+             <p/>
+             The length of the string objects is limited to 128 characters. It is
+             recommended to indicate a namingAuthorityURL in all issued attribute
+             certificates. If a namingAuthorityURL is indicated, the field professionItems
+             of ProfessionInfo should contain only registered titles. If the field
+             professionOIDs exists, it has to contain the OIDs of the professions listed
+             in professionItems in the same order. In general, the field professionInfos
+             should contain only one entry, unless the admissions that are to be listed
+             are logically connected (e.g. they have been issued under the same admission
+             number).
+            
+             @see Org.BouncyCastle.Asn1.IsisMtt.X509.Admissions
+             @see Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo
+             @see Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Constructor from Asn1Sequence.
+             <p/>
+             The sequence is of type ProcurationSyntax:
+             <p/>
+             <pre>
+                 AdmissionSyntax ::= SEQUENCE
+                 {
+                   admissionAuthority GeneralName OPTIONAL,
+                   contentsOfAdmissions SEQUENCE OF Admissions
+                 }
+             <p/>
+                 Admissions ::= SEQUENCE
+                 {
+                   admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+                   namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+                   professionInfos SEQUENCE OF ProfessionInfo
+                 }
+             <p/>
+                 NamingAuthority ::= SEQUENCE
+                 {
+                   namingAuthorityId OBJECT IDENTIFIER OPTIONAL,
+                   namingAuthorityUrl IA5String OPTIONAL,
+                   namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+                 }
+             <p/>
+                 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax.#ctor(Org.BouncyCastle.Asn1.X509.GeneralName,Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Constructor from given details.
+            
+             @param admissionAuthority   The admission authority.
+             @param contentsOfAdmissions The admissions.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <p/>
+             Returns:
+             <p/>
+             <pre>
+                 AdmissionSyntax ::= SEQUENCE
+                 {
+                   admissionAuthority GeneralName OPTIONAL,
+                   contentsOfAdmissions SEQUENCE OF Admissions
+                 }
+             <p/>
+                 Admissions ::= SEQUENCE
+                 {
+                   admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+                   namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+                   professionInfos SEQUENCE OF ProfessionInfo
+                 }
+             <p/>
+                 NamingAuthority ::= SEQUENCE
+                 {
+                   namingAuthorityId OBJECT IDENTIFIER OPTIONAL,
+                   namingAuthorityUrl IA5String OPTIONAL,
+                   namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+                 }
+             <p/>
+                 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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax.GetContentsOfAdmissions">
+            @return Returns the contentsOfAdmissions.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax.AdmissionAuthority">
+            @return Returns the admissionAuthority if present, null otherwise.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.DeclarationOfMajority">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.DeclarationOfMajority.ToAsn1Object">
+             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
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.DeclarationOfMajority.NotYoungerThan">
+            @return notYoungerThan if that's what we are, -1 otherwise
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.MonetaryLimit">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.MonetaryLimit.#ctor(System.String,System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.MonetaryLimit.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority">
+            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
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.String,Org.BouncyCastle.Asn1.X500.DirectoryString)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.ToAsn1Object">
+             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
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.NamingAuthorityID">
+            @return Returns the namingAuthorityID.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.NamingAuthorityText">
+            @return Returns the namingAuthorityText.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.NamingAuthorityUrl">
+            @return Returns the namingAuthorityUrl.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.ProcurationSyntax">
+            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>
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProcurationSyntax.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProcurationSyntax.#ctor(System.String,Org.BouncyCastle.Asn1.X500.DirectoryString,Org.BouncyCastle.Asn1.X509.IssuerSerial)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProcurationSyntax.#ctor(System.String,Org.BouncyCastle.Asn1.X500.DirectoryString,Org.BouncyCastle.Asn1.X509.GeneralName)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProcurationSyntax.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo">
+            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
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Rechtsanwltin">
+            Rechtsanw�ltin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Rechtsanwalt">
+            Rechtsanwalt
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Rechtsbeistand">
+            Rechtsbeistand
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Steuerberaterin">
+            Steuerberaterin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Steuerberater">
+            Steuerberater
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Steuerbevollmchtigte">
+            Steuerbevollm�chtigte
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Steuerbevollmchtigter">
+            Steuerbevollm�chtigter
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Notarin">
+            Notarin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Notar">
+            Notar
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Notarvertreterin">
+            Notarvertreterin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Notarvertreter">
+            Notarvertreter
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Notariatsverwalterin">
+            Notariatsverwalterin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Notariatsverwalter">
+            Notariatsverwalter
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Wirtschaftsprferin">
+            Wirtschaftspr�ferin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Wirtschaftsprfer">
+            Wirtschaftspr�fer
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.VereidigteBuchprferin">
+            Vereidigte Buchpr�ferin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.VereidigterBuchprfer">
+            Vereidigter Buchpr�fer
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Patentanwltin">
+            Patentanw�ltin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Patentanwalt">
+            Patentanwalt
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.#ctor(Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority,Org.BouncyCastle.Asn1.X500.DirectoryString[],Org.BouncyCastle.Asn1.DerObjectIdentifier[],System.String,Org.BouncyCastle.Asn1.Asn1OctetString)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.ToAsn1Object">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.GetProfessionItems">
+            @return Returns the professionItems.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.GetProfessionOids">
+            @return Returns the professionOids.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.AddProfessionInfo">
+            @return Returns the addProfessionInfo.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.NamingAuthority">
+            @return Returns the namingAuthority.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.RegistrationNumber">
+            @return Returns the registrationNumber.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.Restriction">
+            Some other restriction regarding the usage of this certificate.
+            <p/>
+            <pre>
+             RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.Restriction.#ctor(Org.BouncyCastle.Asn1.X500.DirectoryString)">
+             Constructor from DirectoryString.
+             <p/>
+             The DirectoryString is of type RestrictionSyntax:
+             <p/>
+             <pre>
+                  RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+             </pre>
+            
+             @param restriction A IAsn1String.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.Restriction.#ctor(System.String)">
+             Constructor from a given details.
+            
+             @param restriction The description of the restriction.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.Restriction.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <p/>
+             Returns:
+             <p/>
+             <pre>
+                  RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+             <p/>
+             </pre>
+            
+             @return an Asn1Object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Misc.Cast5CbcParameters.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            cast5CBCParameters ::= Sequence {
+                                      iv         OCTET STRING DEFAULT 0,
+                                             -- Initialization vector
+                                      keyLength  Integer
+                                             -- Key length, in bits
+                                 }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Misc.IdeaCbcPar.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            IDEA-CBCPar ::= Sequence {
+                                 iv    OCTET STRING OPTIONAL -- exactly 8 octets
+                             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Misc.NetscapeCertType">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Misc.NetscapeCertType.#ctor(System.Int32)">
+             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)
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Mozilla.PublicKeyAndChallenge">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Nist.NistNamedCurves">
+            Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-2
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Nist.NistNamedCurves.GetByOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Nist.NistNamedCurves.GetOid(System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Nist.NistNamedCurves.GetName(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            return the named curve name represented by the given object identifier.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Nist.NistNamedCurves.Names">
+            returns an enumeration containing the name strings for curves
+            contained in this structure.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Ntt.NttObjectIdentifiers">
+            <summary>From RFC 3657</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.BasicOcspResponse.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.CertID.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.CertStatus.#ctor">
+            create a CertStatus object with a tag of zero.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.CertStatus.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             CertStatus ::= CHOICE {
+                             good        [0]     IMPLICIT Null,
+                             revoked     [1]     IMPLICIT RevokedInfo,
+                             unknown     [2]     IMPLICIT UnknownInfo }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.CrlID.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.OcspRequest.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            OcspRequest     ::=     Sequence {
+                tbsRequest                  TBSRequest,
+                optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.OcspResponse.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            OcspResponse ::= Sequence {
+                responseStatus         OcspResponseStatus,
+                responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.OcspResponseStatus.#ctor(System.Int32)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.Request.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Request         ::=     Sequence {
+                reqCert                     CertID,
+                singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.ResponderID.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            ResponderID ::= CHOICE {
+                 byName          [1] Name,
+                 byKey           [2] KeyHash }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.ResponseBytes.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            ResponseBytes ::=       Sequence {
+                responseType   OBJECT IDENTIFIER,
+                response       OCTET STRING }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.ResponseData.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.RevokedInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            RevokedInfo ::= Sequence {
+                 revocationTime              GeneralizedTime,
+                 revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.ServiceLocator.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            ServiceLocator ::= Sequence {
+                issuer    Name,
+                locator   AuthorityInfoAccessSyntax OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.Signature.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Signature       ::=     Sequence {
+                signatureAlgorithm      AlgorithmIdentifier,
+                signature               BIT STRING,
+                certs               [0] EXPLICIT Sequence OF Certificate OPTIONAL}
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.SingleResponse.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.TbsRequest.ToAsn1Object">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.OidTokenizer">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.AttributePkcs.GetInstance(System.Object)">
+             return an Attribute object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.AttributePkcs.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Attr ::= Sequence {
+                attrType OBJECT IDENTIFIER,
+                attrValues Set OF AttributeValue
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Pkcs.CertificationRequest">
+            Pkcs10 Certfication request object.
+            <pre>
+            CertificationRequest ::= Sequence {
+              certificationRequestInfo  CertificationRequestInfo,
+              signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+              signature                 BIT STRING
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Pkcs.CertificationRequestInfo">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.ContentInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            ContentInfo ::= Sequence {
+                     contentType ContentType,
+                     content
+                     [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Pkcs.EncryptedData">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.EncryptedPrivateKeyInfo.ToAsn1Object">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+                 AlgorithmIdentifier ::= Sequence {
+                                       algorithm OBJECT IDENTIFIER,
+                                       parameters ANY DEFINED BY algorithm OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.MacData.ToAsn1Object">
+            <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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Pkcs.Pfx">
+            the infamous Pfx from Pkcs12
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.PrivateKeyInfo.ToAsn1Object">
+             write out an RSA private key with its associated information
+             as described in Pkcs8.
+             <pre>
+                  PrivateKeyInfo ::= Sequence {
+                                          version Version,
+                                          privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
+                                          privateKey PrivateKey,
+                                          attributes [0] IMPLICIT Attributes OPTIONAL
+                                      }
+                  Version ::= Integer {v1(0)} (v1,...)
+            
+                  PrivateKey ::= OCTET STRING
+            
+                  Attributes ::= Set OF Attr
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.RsaesOaepParameters.#ctor">
+            The default version
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.RsaesOaepParameters.ToAsn1Object">
+             <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.RsaPrivateKeyStructure.ToAsn1Object">
+             This outputs the key in Pkcs1v2 format.
+             <pre>
+                  RsaPrivateKey ::= Sequence {
+                                      version Version,
+                                      modulus Integer, -- n
+                                      publicExponent Integer, -- e
+                                      privateExponent Integer, -- d
+                                      prime1 Integer, -- p
+                                      prime2 Integer, -- q
+                                      exponent1 Integer, -- d mod (p-1)
+                                      exponent2 Integer, -- d mod (q-1)
+                                      coefficient Integer -- (inverse of q) mod p
+                                  }
+            
+                  Version ::= Integer
+             </pre>
+             <p>This routine is written to output Pkcs1 version 0, private keys.</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.RsassaPssParameters.#ctor">
+            The default version
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.RsassaPssParameters.ToAsn1Object">
+             <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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Pkcs.SignedData">
+            a Pkcs#7 signed data object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.SignedData.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             SignedData ::= Sequence {
+                 version Version,
+                 digestAlgorithms DigestAlgorithmIdentifiers,
+                 contentInfo ContentInfo,
+                 certificates
+                     [0] IMPLICIT ExtendedCertificatesAndCertificates
+                              OPTIONAL,
+                 crls
+                     [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+                 signerInfos SignerInfos }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Pkcs.SignerInfo">
+            a Pkcs#7 signer info object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.SignerInfo.ToAsn1Object">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Sec.ECPrivateKeyStructure">
+            the elliptic curve private key object from SEC 1
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Sec.ECPrivateKeyStructure.ToAsn1Object">
+            ECPrivateKey ::= SEQUENCE {
+                version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+                privateKey OCTET STRING,
+                parameters [0] Parameters OPTIONAL,
+                publicKey [1] BIT STRING OPTIONAL }
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetOid(System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetName(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            return the named curve name represented by the given object identifier.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Sec.SecNamedCurves.Names">
+            returns an enumeration containing the name strings for curves
+            contained in this structure.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.Sec.SecObjectIdentifiers.EllipticCurve">
+            EllipticCurve OBJECT IDENTIFIER ::= {
+                  iso(1) identified-organization(3) certicom(132) curve(0)
+            }
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Smime.SmimeCapabilities">
+            Handler class for dealing with S/MIME Capabilities
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.Smime.SmimeCapabilities.PreferSignedData">
+            general preferences
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.Smime.SmimeCapabilities.DesCbc">
+            encryption algorithms preferences
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Smime.SmimeCapabilities.GetInstance(System.Object)">
+             return an Attr object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Smime.SmimeCapabilities.GetCapabilitiesForOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            returns an ArrayList with 0 or more objects of all the capabilities
+            matching the passed in capability Oid. If the Oid passed is null the
+            entire set is returned.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Smime.SmimeCapabilities.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            SMIMECapabilities ::= Sequence OF SMIMECapability
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttributeX509.GetInstance(System.Object)">
+             return an Attr object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttributeX509.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Attr ::= Sequence {
+                attrType OBJECT IDENTIFIER,
+                attrValues Set OF AttributeValue
+            }
+            </pre>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.Smime.SmimeCapability.PreferSignedData">
+            general preferences
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.Smime.SmimeCapability.DesCbc">
+            encryption algorithms preferences
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Smime.SmimeCapability.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            SMIMECapability ::= Sequence {
+                capabilityID OBJECT IDENTIFIER,
+                parameters ANY DEFINED BY capabilityID OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Smime.SmimeCapabilityVector">
+            Handler for creating a vector S/MIME Capabilities
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Smime.SmimeEncryptionKeyPreferenceAttribute">
+            The SmimeEncryptionKeyPreference object.
+            <pre>
+            SmimeEncryptionKeyPreference ::= CHOICE {
+                issuerAndSerialNumber   [0] IssuerAndSerialNumber,
+                receipentKeyId          [1] RecipientKeyIdentifier,
+                subjectAltKeyIdentifier [2] SubjectKeyIdentifier
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Smime.SmimeEncryptionKeyPreferenceAttribute.#ctor(Org.BouncyCastle.Asn1.Asn1OctetString)">
+            @param sKeyId the subjectKeyIdentifier value (normally the X.509 one)
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.TeleTrust.TeleTrusTNamedCurves">
+            elliptic curves defined in "ECC Brainpool Standard Curves and Curve Generation"
+            http://www.ecc-brainpool.org/download/draft_pkix_additional_ecc_dp.txt
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.TeleTrust.TeleTrusTNamedCurves.GetByOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.TeleTrust.TeleTrusTNamedCurves.GetOid(System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.TeleTrust.TeleTrusTNamedCurves.GetName(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            return the named curve name represented by the given object identifier.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.TeleTrust.TeleTrusTNamedCurves.Names">
+            returns an enumeration containing the name strings for curves
+            contained in this structure.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Tsp.Accuracy.ToAsn1Object">
+            <pre>
+            Accuracy ::= SEQUENCE {
+                        seconds        INTEGER              OPTIONAL,
+                        millis     [0] INTEGER  (1..999)    OPTIONAL,
+                        micros     [1] INTEGER  (1..999)    OPTIONAL
+                        }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Tsp.MessageImprint.GetInstance(System.Object)">
+            @param o
+            @return a MessageImprint object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Tsp.MessageImprint.ToAsn1Object">
+            <pre>
+               MessageImprint ::= SEQUENCE  {
+                  hashAlgorithm                AlgorithmIdentifier,
+                  hashedMessage                OCTET STRING  }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Tsp.TimeStampReq.ToAsn1Object">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Tsp.TimeStampResp.ToAsn1Object">
+            <pre>
+            TimeStampResp ::= SEQUENCE  {
+              status                  PkiStatusInfo,
+              timeStampToken          TimeStampToken     OPTIONAL  }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Tsp.TstInfo.ToAsn1Object">
+             <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Utilities.Asn1Dump.AsString(System.String,System.Boolean,Org.BouncyCastle.Asn1.Asn1Object,System.Text.StringBuilder)">
+             dump a Der object as a formatted string with indentation
+            
+             @param obj the Asn1Object to be dumped out.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Utilities.Asn1Dump.DumpAsString(Org.BouncyCastle.Asn1.Asn1Encodable)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Utilities.Asn1Dump.DumpAsString(Org.BouncyCastle.Asn1.Asn1Encodable,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X500.DirectoryString.ToAsn1Object">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.AccessDescription">
+            The AccessDescription object.
+            <pre>
+            AccessDescription  ::=  SEQUENCE {
+                  accessMethod          OBJECT IDENTIFIER,
+                  accessLocation        GeneralName  }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AccessDescription.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.X509.GeneralName)">
+            create an AccessDescription with the oid and location provided.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.AccessDescription.AccessMethod">
+            
+             @return the access method.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.AccessDescription.AccessLocation">
+            
+             @return the access location
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttCertIssuer.#ctor(Org.BouncyCastle.Asn1.X509.GeneralNames)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttCertIssuer.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttCertValidityPeriod.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             AttCertValidityPeriod  ::= Sequence {
+                  notBeforeTime  GeneralizedTime,
+                  notAfterTime   GeneralizedTime
+             }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttributeCertificate.GetInstance(System.Object)">
+            @param obj
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttributeCertificate.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             AttributeCertificate ::= Sequence {
+                  acinfo               AttributeCertificateInfo,
+                  signatureAlgorithm   AlgorithmIdentifier,
+                  signatureValue       BIT STRING
+             }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttributeCertificateInfo.ToAsn1Object">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.AuthorityInformationAccess">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityInformationAccess.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.X509.GeneralName)">
+            create an AuthorityInformationAccess with the oid and location provided.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier">
+             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>
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier.#ctor(Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo)">
+                     *
+                     * 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>
+                     *
+                     *
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier.#ctor(Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo,Org.BouncyCastle.Asn1.X509.GeneralNames,Org.BouncyCastle.Math.BigInteger)">
+            create an AuthorityKeyIdentifier with the GeneralNames tag and
+            the serial number provided as well.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier.#ctor(Org.BouncyCastle.Asn1.X509.GeneralNames,Org.BouncyCastle.Math.BigInteger)">
+            create an AuthorityKeyIdentifier with the GeneralNames tag and
+            the serial number provided.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier.#ctor(System.Byte[])">
+            create an AuthorityKeyIdentifier with a precomputed key identifier
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier.#ctor(System.Byte[],Org.BouncyCastle.Asn1.X509.GeneralNames,Org.BouncyCastle.Math.BigInteger)">
+            create an AuthorityKeyIdentifier with a precomupted key identifier
+            and the GeneralNames tag and the serial number provided as well.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.BasicConstraints.#ctor(System.Int32)">
+             create a cA=true object for the given path length constraint.
+            
+             @param pathLenConstraint
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.BasicConstraints.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            BasicConstraints := Sequence {
+               cA                  Boolean DEFAULT FALSE,
+               pathLenConstraint   Integer (0..MAX) OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.CertificateList">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.CertificatePair">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.CertificatePair.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.CertificatePair.#ctor(Org.BouncyCastle.Asn1.X509.X509CertificateStructure,Org.BouncyCastle.Asn1.X509.X509CertificateStructure)">
+             Constructor from a given details.
+            
+             @param forward Certificates issued to this CA.
+             @param reverse Certificates issued by this CA to other CAs.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.CertificatePair.ToAsn1Object">
+             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
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.CertificatePair.Forward">
+            @return Returns the forward.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.CertificatePair.Reverse">
+            @return Returns the reverse.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.CertPolicyID">
+             CertPolicyId, used in the CertificatePolicies and PolicyMappings
+             X509V3 Extensions.
+            
+             <pre>
+                 CertPolicyId ::= OBJECT IDENTIFIER
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.CrlDistPoint.GetDistributionPoints">
+             Return the distribution points making up the sequence.
+            
+             @return DistributionPoint[]
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.CrlDistPoint.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            CrlDistPoint ::= Sequence SIZE {1..MAX} OF DistributionPoint
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.CrlNumber">
+            The CRLNumber object.
+            <pre>
+            CRLNumber::= Integer(0..MAX)
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.CrlReason">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.DigestInfo">
+            The DigestInfo object.
+            <pre>
+            DigestInfo::=Sequence{
+                     digestAlgorithm  AlgorithmIdentifier,
+                     digest OCTET STRING }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.DisplayText">
+             <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
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.DisplayText.ContentTypeIA5String">
+             Constant corresponding to ia5String encoding.
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.DisplayText.ContentTypeBmpString">
+             Constant corresponding to bmpString encoding.
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.DisplayText.ContentTypeUtf8String">
+             Constant corresponding to utf8String encoding.
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.DisplayText.ContentTypeVisibleString">
+             Constant corresponding to visibleString encoding.
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.DisplayText.DisplayTextMaximumSize">
+             Describe constant <code>DisplayTextMaximumSize</code> here.
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.DisplayText.#ctor(System.Int32,System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.DisplayText.#ctor(System.String)">
+             Creates a new <code>DisplayText</code> instance.
+            
+             @param text the text to encapsulate. Strings longer than 200
+             characters are truncated.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.DisplayText.#ctor(Org.BouncyCastle.Asn1.IAsn1String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.DisplayText.GetString">
+             Returns the stored <code>string</code> object.
+            
+             @return the stored text as a <code>string</code>.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.DistributionPoint">
+            The DistributionPoint object.
+            <pre>
+            DistributionPoint ::= Sequence {
+                 distributionPoint [0] DistributionPointName OPTIONAL,
+                 reasons           [1] ReasonFlags OPTIONAL,
+                 cRLIssuer         [2] GeneralNames OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.DistributionPointName">
+            The DistributionPointName object.
+            <pre>
+            DistributionPointName ::= CHOICE {
+                fullName                 [0] GeneralNames,
+                nameRelativeToCRLIssuer  [1] RDN
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.ExtendedKeyUsage">
+            The extendedKeyUsage object.
+            <pre>
+                 extendedKeyUsage ::= Sequence SIZE (1..MAX) OF KeyPurposeId
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.ExtendedKeyUsage.GetAllUsages">
+            Returns all extended key usages.
+            The returned ArrayList contains DerObjectIdentifier instances.
+            @return An ArrayList with all key purposes.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.GeneralName">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.GeneralName.#ctor(Org.BouncyCastle.Asn1.Asn1Object,System.Int32)">
+             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].
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.GeneralName.#ctor(System.Int32,System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.GeneralNames.#ctor(Org.BouncyCastle.Asn1.X509.GeneralName)">
+            <summary>Construct a GeneralNames object containing one GeneralName.</summary>
+            <param name="name">The name to be contained.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.GeneralNames.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            GeneralNames ::= Sequence SIZE {1..MAX} OF GeneralName
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.GeneralSubtree">
+             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
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.GeneralSubtree.#ctor(Org.BouncyCastle.Asn1.X509.GeneralName,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.GeneralSubtree.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Holder">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.#ctor(Org.BouncyCastle.Asn1.Asn1TaggedObject)">
+            Constructor for a holder for an v1 attribute certificate.
+            
+            @param tagObj The ASN.1 tagged holder object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            Constructor for a holder for an v2 attribute certificate. *
+            
+            @param seq The ASN.1 sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.#ctor(Org.BouncyCastle.Asn1.X509.IssuerSerial,System.Int32)">
+            Constructs a holder from a IssuerSerial.
+            @param baseCertificateID The IssuerSerial.
+            @param version The version of the attribute certificate. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.#ctor(Org.BouncyCastle.Asn1.X509.GeneralNames)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.#ctor(Org.BouncyCastle.Asn1.X509.GeneralNames,System.Int32)">
+            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. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.#ctor(Org.BouncyCastle.Asn1.X509.ObjectDigestInfo)">
+            Constructs a holder from an object digest info.
+            
+            @param objectDigestInfo The object digest info object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.ToAsn1Object">
+            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>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.Holder.Version">
+            Returns 1 for v2 attribute certificates or 0 for v1 attribute
+            certificates. 
+            @return The version of the attribute certificate.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.Holder.EntityName">
+            Returns the entityName for an v2 attribute certificate or the subjectName
+            for an v1 attribute certificate.
+            
+            @return The entityname or subjectname.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.IetfAttrSyntax">
+            Implementation of <code>IetfAttrSyntax</code> as specified by RFC3281.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.IetfAttrSyntax.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.IetfAttrSyntax.ToAsn1Object">
+            
+             <pre>
+            
+              IetfAttrSyntax ::= Sequence {
+                policyAuthority [0] GeneralNames OPTIONAL,
+                values Sequence OF CHOICE {
+                  octets OCTET STRING,
+                  oid OBJECT IDENTIFIER,
+                  string UTF8String
+                }
+              }
+            
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.IssuerSerial.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             IssuerSerial  ::=  Sequence {
+                  issuer         GeneralNames,
+                  serial         CertificateSerialNumber,
+                  issuerUid      UniqueIdentifier OPTIONAL
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.IssuingDistributionPoint">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.IssuingDistributionPoint.#ctor(Org.BouncyCastle.Asn1.X509.DistributionPointName,System.Boolean,System.Boolean,Org.BouncyCastle.Asn1.X509.ReasonFlags,System.Boolean,System.Boolean)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.IssuingDistributionPoint.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            Constructor from Asn1Sequence
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.IssuingDistributionPoint.DistributionPoint">
+            @return Returns the distributionPoint.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.IssuingDistributionPoint.OnlySomeReasons">
+            @return Returns the onlySomeReasons.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.KeyPurposeID">
+            The KeyPurposeID object.
+            <pre>
+                KeyPurposeID ::= OBJECT IDENTIFIER
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.KeyUsage">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.KeyUsage.#ctor(System.Int32)">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.NameConstraints.#ctor(System.Collections.IList,System.Collections.IList)">
+             Constructor from a given details.
+            
+             <p>permitted and excluded are Vectors of GeneralSubtree objects.</p>
+            
+             @param permitted Permitted subtrees
+             @param excluded Excluded subtrees
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.NoticeReference">
+             <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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.NoticeReference.#ctor(System.String,System.Collections.IList)">
+             Creates a new <code>NoticeReference</code> instance.
+            
+             @param orgName a <code>string</code> value
+             @param numbers a <code>ArrayList</code> value
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.NoticeReference.#ctor(System.String,Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Creates a new <code>NoticeReference</code> instance.
+            
+             @param orgName a <code>string</code> value
+             @param numbers an <code>Asn1Sequence</code> value
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.NoticeReference.#ctor(System.Int32,System.String,Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.NoticeReference.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.NoticeReference.ToAsn1Object">
+             Describe <code>ToAsn1Object</code> method here.
+            
+             @return a <code>Asn1Object</code> value
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.ObjectDigestInfo">
+            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>
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.ObjectDigestInfo.PublicKey">
+            The public key is hashed.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.ObjectDigestInfo.PublicKeyCert">
+            The public key certificate is hashed.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.ObjectDigestInfo.OtherObjectDigest">
+            An other object is hashed.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.ObjectDigestInfo.#ctor(System.Int32,System.String,Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier,System.Byte[])">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.ObjectDigestInfo.ToAsn1Object">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.PolicyMappings">
+             PolicyMappings V3 extension, described in RFC3280.
+             <pre>
+                PolicyMappings ::= Sequence SIZE (1..MAX) OF Sequence {
+                  issuerDomainPolicy      CertPolicyId,
+                  subjectDomainPolicy     CertPolicyId }
+             </pre>
+            
+             @see <a href="http://www.faqs.org/rfc/rfc3280.txt">RFC 3280, section 4.2.1.6</a>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.PolicyMappings.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Creates a new <code>PolicyMappings</code> instance.
+            
+             @param seq an <code>Asn1Sequence</code> constructed as specified
+             in RFC 3280
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.PolicyMappings.#ctor(System.Collections.IDictionary)">
+             Creates a new <code>PolicyMappings</code> instance.
+            
+             @param mappings a <code>HashMap</code> value that maps
+             <code>string</code> oids
+             to other <code>string</code> oids.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.PolicyQualifierID">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.PolicyQualifierInfo">
+             Policy qualifiers, used in the X509V3 CertificatePolicies
+             extension.
+            
+             <pre>
+               PolicyQualifierInfo ::= Sequence {
+                   policyQualifierId  PolicyQualifierId,
+                   qualifier          ANY DEFINED BY policyQualifierId }
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.PolicyQualifierInfo.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.Asn1Encodable)">
+             Creates a new <code>PolicyQualifierInfo</code> instance.
+            
+             @param policyQualifierId a <code>PolicyQualifierId</code> value
+             @param qualifier the qualifier, defined by the above field.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.PolicyQualifierInfo.#ctor(System.String)">
+             Creates a new <code>PolicyQualifierInfo</code> containing a
+             cPSuri qualifier.
+            
+             @param cps the CPS (certification practice statement) uri as a
+             <code>string</code>.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.PolicyQualifierInfo.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Creates a new <code>PolicyQualifierInfo</code> instance.
+            
+             @param as <code>PolicyQualifierInfo</code> X509 structure
+             encoded as an Asn1Sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.PolicyQualifierInfo.ToAsn1Object">
+             Returns a Der-encodable representation of this instance.
+            
+             @return a <code>Asn1Object</code> value
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.PrivateKeyUsagePeriod">
+            <remarks>
+            <pre>
+            PrivateKeyUsagePeriod ::= SEQUENCE
+            {
+            notBefore       [0]     GeneralizedTime OPTIONAL,
+            notAfter        [1]     GeneralizedTime OPTIONAL }
+            </pre>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Qualified.BiometricData">
+            The BiometricData object.
+            <pre>
+            BiometricData  ::=  SEQUENCE {
+                  typeOfBiometricData  TypeOfBiometricData,
+                  hashAlgorithm        AlgorithmIdentifier,
+                  biometricDataHash    OCTET STRING,
+                  sourceDataUri        IA5String OPTIONAL  }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Qualified.Iso4217CurrencyCode">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Qualified.MonetaryValue">
+            The MonetaryValue object.
+            <pre>
+            MonetaryValue  ::=  SEQUENCE {
+                  currency              Iso4217CurrencyCode,
+                  amount               INTEGER,
+                  exponent             INTEGER }
+            -- value = amount * 10^exponent
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Qualified.QCStatement">
+            The QCStatement object.
+            <pre>
+            QCStatement ::= SEQUENCE {
+              statementId        OBJECT IDENTIFIER,
+              statementInfo      ANY DEFINED BY statementId OPTIONAL}
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Qualified.SemanticsInformation">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Qualified.TypeOfBiometricData">
+             The TypeOfBiometricData object.
+             <pre>
+             TypeOfBiometricData ::= CHOICE {
+               predefinedBiometricType   PredefinedBiometricType,
+               biometricDataOid          OBJECT IDENTIFIER }
+            
+             PredefinedBiometricType ::= INTEGER {
+               picture(0),handwritten-signature(1)}
+               (picture|handwritten-signature)
+             </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.ReasonFlags">
+            The ReasonFlags object.
+            <pre>
+            ReasonFlags ::= BIT STRING {
+               unused(0),
+               keyCompromise(1),
+               cACompromise(2),
+               affiliationChanged(3),
+               superseded(4),
+               cessationOfOperation(5),
+               certficateHold(6)
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.ReasonFlags.#ctor(System.Int32)">
+            @param reasons - the bitwise OR of the Key Reason flags giving the
+            allowed uses for the key.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.RoleSyntax">
+             Implementation of the RoleSyntax object as specified by the RFC3281.
+            
+             <pre>
+             RoleSyntax ::= SEQUENCE {
+                             roleAuthority  [0] GeneralNames OPTIONAL,
+                             roleName       [1] GeneralName
+                       }
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.GetInstance(System.Object)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.#ctor(Org.BouncyCastle.Asn1.X509.GeneralNames,Org.BouncyCastle.Asn1.X509.GeneralName)">
+            Constructor.
+            @param roleAuthority the role authority of this RoleSyntax.
+            @param roleName    the role name of this RoleSyntax.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.#ctor(Org.BouncyCastle.Asn1.X509.GeneralName)">
+            Constructor. Invoking this constructor is the same as invoking
+            <code>new RoleSyntax(null, roleName)</code>.
+            @param roleName    the role name of this RoleSyntax.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.#ctor(System.String)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.GetRoleNameAsString">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.GetRoleAuthorityAsString">
+            Gets the role authority as a <code>string[]</code> object.
+            @return the role authority of this RoleSyntax represented as a
+            <code>string[]</code> array.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.ToAsn1Object">
+             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>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.RoleSyntax.RoleAuthority">
+            Gets the role authority of this RoleSyntax.
+            @return    an instance of <code>GeneralNames</code> holding the
+            role authority of this RoleSyntax.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.RoleSyntax.RoleName">
+            Gets the role name of this RoleSyntax.
+            @return    an instance of <code>GeneralName</code> holding the
+            role name of this RoleSyntax.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RsaPublicKeyStructure.ToAsn1Object">
+            This outputs the key in Pkcs1v2 format.
+            <pre>
+                 RSAPublicKey ::= Sequence {
+                                     modulus Integer, -- n
+                                     publicExponent Integer, -- e
+                                 }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym">
+            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
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym.#ctor(Org.BouncyCastle.Asn1.X500.DirectoryString)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym.#ctor(System.String)">
+             Constructor from a given details.
+            
+             @param pseudonym The pseudonym.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym.#ctor(Org.BouncyCastle.Asn1.X500.DirectoryString,Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Constructor from a given details.
+            
+             @param surname   The surname.
+             @param givenName A sequence of directory strings making up the givenName
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.SigI.PersonalData">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.PersonalData.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.PersonalData.#ctor(Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Asn1.DerGeneralizedTime,Org.BouncyCastle.Asn1.X500.DirectoryString,System.String,Org.BouncyCastle.Asn1.X500.DirectoryString)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.PersonalData.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers">
+            Object Identifiers of SigI specifciation (German Signature Law
+            Interoperability specification).
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers.IdSigIKP">
+            Key purpose IDs for German SigI (Signature Interoperability
+            Specification)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers.IdSigICP">
+            Certificate policy IDs for German SigI (Signature Interoperability
+            Specification)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers.IdSigION">
+            Other Name IDs for German SigI (Signature Interoperability Specification)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers.IdSigIKPDirectoryService">
+            To be used for for the generation of directory service certificates.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers.IdSigIONPersonalData">
+            ID for PersonalData
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers.IdSigICPSigConform">
+            Certificate is conform to german signature law.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes">
+             This extension may contain further X.500 attributes of the subject. See also
+             RFC 3039.
+            
+             <pre>
+                 SubjectDirectoryAttributes ::= Attributes
+                 Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+                 Attribute ::= SEQUENCE
+                 {
+                   type AttributeType
+                   values SET OF AttributeValue
+                 }
+            
+                 AttributeType ::= OBJECT IDENTIFIER
+                 AttributeValue ::= ANY DEFINED BY AttributeType
+             </pre>
+            
+             @see org.bouncycastle.asn1.x509.X509Name for AttributeType ObjectIdentifiers.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Constructor from Asn1Sequence.
+            
+             The sequence is of type SubjectDirectoryAttributes:
+            
+             <pre>
+                  SubjectDirectoryAttributes ::= Attributes
+                  Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+                  Attribute ::= SEQUENCE
+                  {
+                    type AttributeType
+                    values SET OF AttributeValue
+                  }
+            
+                  AttributeType ::= OBJECT IDENTIFIER
+                  AttributeValue ::= ANY DEFINED BY AttributeType
+             </pre>
+            
+             @param seq
+                        The ASN.1 sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes.#ctor(System.Collections.IList)">
+             Constructor from an ArrayList of attributes.
+            
+             The ArrayList consists of attributes of type {@link Attribute Attribute}
+            
+             @param attributes The attributes.
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+            
+             Returns:
+            
+             <pre>
+                  SubjectDirectoryAttributes ::= Attributes
+                  Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+                  Attribute ::= SEQUENCE
+                  {
+                    type AttributeType
+                    values SET OF AttributeValue
+                  }
+            
+                  AttributeType ::= OBJECT IDENTIFIER
+                  AttributeValue ::= ANY DEFINED BY AttributeType
+             </pre>
+            
+             @return a DERObject
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes.Attributes">
+            @return Returns the attributes.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.SubjectKeyIdentifier">
+            The SubjectKeyIdentifier object.
+            <pre>
+            SubjectKeyIdentifier::= OCTET STRING
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectKeyIdentifier.#ctor(Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo)">
+             Calculates the keyIdentifier using a SHA1 hash over the BIT STRING
+             from SubjectPublicKeyInfo as defined in RFC3280.
+            
+             @param spki the subject public key info.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectKeyIdentifier.CreateSha1KeyIdentifier(Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectKeyIdentifier.CreateTruncatedSha1KeyIdentifier(Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo.GetPublicKey">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            SubjectPublicKeyInfo ::= Sequence {
+                                     algorithm AlgorithmIdentifier,
+                                     publicKey BIT STRING }
+            </pre>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo.PublicKeyData">
+            for when the public key is raw bits...
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Target">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Target.GetInstance(System.Object)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Target.#ctor(Org.BouncyCastle.Asn1.Asn1TaggedObject)">
+            Constructor from Asn1TaggedObject.
+            
+            @param tagObj The tagged object.
+            @throws ArgumentException if the encoding is wrong.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Target.#ctor(Org.BouncyCastle.Asn1.X509.Target.Choice,Org.BouncyCastle.Asn1.X509.GeneralName)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Target.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            
+            Returns:
+            
+            <pre>
+                Target  ::= CHOICE {
+                  targetName          [0] GeneralName,
+                  targetGroup         [1] GeneralName,
+                  targetCert          [2] TargetCert
+                }
+            </pre>
+            
+            @return an Asn1Object
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.Target.TargetGroup">
+            @return Returns the targetGroup.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.Target.TargetName">
+            @return Returns the targetName.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.TargetInformation">
+            Target information extension for attributes certificates according to RFC
+            3281.
+            
+            <pre>
+                      SEQUENCE OF Targets
+            </pre>
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.TargetInformation.GetInstance(System.Object)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.TargetInformation.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            Constructor from a Asn1Sequence.
+            
+            @param seq The Asn1Sequence.
+            @throws ArgumentException if the sequence does not contain
+                        correctly encoded Targets elements.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.TargetInformation.GetTargetsObjects">
+            Returns the targets in this target information extension.
+            <p>
+            The ArrayList is cloned before it is returned.</p>
+            
+            @return Returns the targets.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.TargetInformation.#ctor(Org.BouncyCastle.Asn1.X509.Targets)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.TargetInformation.#ctor(Org.BouncyCastle.Asn1.X509.Target[])">
+             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}.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.TargetInformation.ToAsn1Object">
+            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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Targets">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Targets.GetInstance(System.Object)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Targets.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            Constructor from Asn1Sequence.
+            
+            @param targets The ASN.1 SEQUENCE.
+            @throws ArgumentException if the contents of the sequence are
+                        invalid.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Targets.#ctor(Org.BouncyCastle.Asn1.X509.Target[])">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Targets.GetTargets">
+            Returns the targets in an <code>ArrayList</code>.
+            <p>
+            The ArrayList is cloned before it is returned.</p>
+            
+            @return Returns the targets.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Targets.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            
+            Returns:
+            
+            <pre>
+                       Targets ::= SEQUENCE OF Target
+            </pre>
+            
+            @return an Asn1Object
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.TbsCertificateStructure">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.TbsCertificateList">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Time.#ctor(System.DateTime)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Time.ToDateTime">
+            <summary>
+            Return our time as DateTime.
+            </summary>
+            <returns>A date time.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Time.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Time ::= CHOICE {
+                        utcTime        UTCTime,
+                        generalTime    GeneralizedTime }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.UserNotice">
+             <code>UserNotice</code> class, used in
+             <code>CertificatePolicies</code> X509 extensions (in policy
+             qualifiers).
+             <pre>
+             UserNotice ::= Sequence {
+                  noticeRef        NoticeReference OPTIONAL,
+                  explicitText     DisplayText OPTIONAL}
+            
+             </pre>
+            
+             @see PolicyQualifierId
+             @see PolicyInformation
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.UserNotice.#ctor(Org.BouncyCastle.Asn1.X509.NoticeReference,Org.BouncyCastle.Asn1.X509.DisplayText)">
+             Creates a new <code>UserNotice</code> instance.
+            
+             @param noticeRef a <code>NoticeReference</code> value
+             @param explicitText a <code>DisplayText</code> value
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.UserNotice.#ctor(Org.BouncyCastle.Asn1.X509.NoticeReference,System.String)">
+             Creates a new <code>UserNotice</code> instance.
+            
+             @param noticeRef a <code>NoticeReference</code> value
+             @param str the explicitText field as a string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.UserNotice.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.V1TbsCertificateGenerator">
+             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>
+            
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.V2AttributeCertificateInfoGenerator">
+             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>
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.V2AttributeCertificateInfoGenerator.AddAttribute(Org.BouncyCastle.Asn1.X509.AttributeX509)">
+            @param attribute
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.V2Form.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             V2Form ::= Sequence {
+                  issuerName            GeneralNames  OPTIONAL,
+                  baseCertificateID     [0] IssuerSerial  OPTIONAL,
+                  objectDigestInfo      [1] ObjectDigestInfo  OPTIONAL
+                    -- issuerName MUST be present in this profile
+                    -- baseCertificateID and objectDigestInfo MUST NOT
+                    -- be present in this profile
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.V2TbsCertListGenerator">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.V3TbsCertificateGenerator">
+             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>
+            
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509CertificateStructure">
+            an X509Certificate structure.
+            <pre>
+             Certificate ::= Sequence {
+                 tbsCertificate          TbsCertificate,
+                 signatureAlgorithm      AlgorithmIdentifier,
+                 signature               BIT STRING
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509DefaultEntryConverter">
+            The default converter for X509 DN entries when going from their
+            string value to ASN.1 strings.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509NameEntryConverter">
+                 * 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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509NameEntryConverter.ConvertHexEncoded(System.String,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509NameEntryConverter.CanBePrintable(System.String)">
+            return true if the passed in string can be represented without
+            loss as a PrintableString, false otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509NameEntryConverter.GetConvertedValue(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509DefaultEntryConverter.GetConvertedValue(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.String)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509Extension">
+            an object for the elements in the X.509 V3 extension block.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extension.ConvertValueToObject(Org.BouncyCastle.Asn1.X509.X509Extension)">
+            <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="T:System.ArgumentException">If conversion is not possible.</exception>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectDirectoryAttributes">
+            Subject Directory Attributes
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectKeyIdentifier">
+            Subject Key Identifier
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.KeyUsage">
+            Key Usage
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.PrivateKeyUsagePeriod">
+            Private Key Usage Period
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectAlternativeName">
+            Subject Alternative Name
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.IssuerAlternativeName">
+            Issuer Alternative Name
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.BasicConstraints">
+            Basic Constraints
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.CrlNumber">
+            CRL Number
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.ReasonCode">
+            Reason code
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.InstructionCode">
+            Hold Instruction Code
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.InvalidityDate">
+            Invalidity Date
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.DeltaCrlIndicator">
+            Delta CRL indicator
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.IssuingDistributionPoint">
+            Issuing Distribution Point
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.CertificateIssuer">
+            Certificate Issuer
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.NameConstraints">
+            Name Constraints
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.CrlDistributionPoints">
+            CRL Distribution Points
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.CertificatePolicies">
+            Certificate Policies
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.PolicyMappings">
+            Policy Mappings
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.AuthorityKeyIdentifier">
+            Authority Key Identifier
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.PolicyConstraints">
+            Policy Constraints
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.ExtendedKeyUsage">
+            Extended Key Usage
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.FreshestCrl">
+            Freshest CRL
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.InhibitAnyPolicy">
+            Inhibit Any Policy
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.AuthorityInfoAccess">
+            Authority Info Access
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectInfoAccess">
+            Subject Info Access
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.LogoType">
+            Logo Type
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.BiometricInfo">
+            BiometricInfo
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.QCStatements">
+            QCStatements
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.AuditIdentity">
+            Audit identity extension in attribute certificates.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.NoRevAvail">
+            NoRevAvail extension in attribute certificates.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.TargetInformation">
+            TargetInformation extension in attribute certificates.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extensions.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Constructor from Asn1Sequence.
+            
+             the extensions are a list of constructed sequences, either with (Oid, OctetString) or (Oid, Boolean, OctetString)
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extensions.#ctor(System.Collections.IDictionary)">
+            constructor from a table of extensions.
+            <p>
+            it's is assumed the table contains Oid/string pairs.</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extensions.#ctor(System.Collections.IList,System.Collections.IDictionary)">
+            Constructor from a table of extensions with ordering.
+            <p>
+            It's is assumed the table contains Oid/string pairs.</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extensions.#ctor(System.Collections.IList,System.Collections.IList)">
+             Constructor from two vectors
+            
+             @param objectIDs an ArrayList of the object identifiers.
+             @param values an ArrayList of the extension values.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extensions.GetExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             return the extension represented by the object identifier
+             passed in.
+            
+             @return the extension if it's present, null otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extensions.ToAsn1Object">
+             <pre>
+                 Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
+            
+                 Extension         ::=   SEQUENCE {
+                    extnId            EXTENSION.&amp;id ({ExtensionSet}),
+                    critical          BOOLEAN DEFAULT FALSE,
+                    extnValue         OCTET STRING }
+             </pre>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.X509Extensions.ExtensionOids">
+            return an Enumeration of the extension field's object ids.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509ExtensionsGenerator">
+            <remarks>Generator for X.509 extensions</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509ExtensionsGenerator.Reset">
+            <summary>Reset the generator</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509ExtensionsGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509ExtensionsGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,System.Byte[])">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509ExtensionsGenerator.Generate">
+            <summary>Generate an X509Extensions object based on the current state of the generator.</summary>
+            <returns>An <c>X509Extensions</c> object</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.X509ExtensionsGenerator.IsEmpty">
+            <summary>Return true if there are no extension present in this generator.</summary>
+            <returns>True if empty, false otherwise</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509Name">
+             <pre>
+                 RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+            
+                 RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+            
+                 AttributeTypeAndValue ::= SEQUENCE {
+                                               type  OBJECT IDENTIFIER,
+                                               value ANY }
+             </pre>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.C">
+            country code - StringType(SIZE(2))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.O">
+            organization - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.OU">
+            organizational unit name - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.T">
+            Title
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.CN">
+            common name - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.Street">
+            street - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.SerialNumber">
+            device serial number name - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.L">
+            locality name - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.ST">
+            state, or province name - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.Surname">
+            Naming attributes of type X520name
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.BusinessCategory">
+            businessCategory - DirectoryString(SIZE(1..128)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.PostalCode">
+            postalCode - DirectoryString(SIZE(1..40)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.DnQualifier">
+            dnQualifier - DirectoryString(SIZE(1..64)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.Pseudonym">
+            RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.DateOfBirth">
+            RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.PlaceOfBirth">
+            RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.Gender">
+            RFC 3039 DateOfBirth - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.CountryOfCitizenship">
+            RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+            codes only
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.CountryOfResidence">
+            RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+            codes only
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.NameAtBirth">
+            ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.PostalAddress">
+            RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
+            DirectoryString(SIZE(1..30))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.DmdName">
+            RFC 2256 dmdName
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.TelephoneNumber">
+            id-at-telephoneNumber
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.Name">
+            id-at-name
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.EmailAddress">
+            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>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.UnstructuredName">
+            more from PKCS#9
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.E">
+            email address in Verisign certificates
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.UID">
+            LDAP User id.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.DefaultSymbols">
+            default look up table translating OID values into their common symbols following
+            the convention in RFC 2253 with a few extras
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.RFC2253Symbols">
+            look up table translating OID values into their common symbols following the convention in RFC 2253
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.RFC1779Symbols">
+             look up table translating OID values into their common symbols following the convention in RFC 1779
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.DefaultLookup">
+            look up table translating common symbols into their OIDS.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             Return a X509Name based on the passed in tagged object.
+            
+             @param obj tag object holding name.
+             @param explicitly true if explicitly tagged false otherwise.
+             @return the X509Name
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Constructor from Asn1Sequence
+            
+             the principal will be a list of constructed sets, each containing an (OID, string) pair.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Collections.IList,System.Collections.IDictionary)">
+            Constructor from a table of attributes with ordering.
+            <p>
+            it's is assumed the table contains OID/string pairs, and the contents
+            of the table are copied into an internal table as part of the
+            construction process. The ordering ArrayList should contain the OIDs
+            in the order they are meant to be encoded or printed in ToString.</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Collections.IList,System.Collections.IDictionary,Org.BouncyCastle.Asn1.X509.X509NameEntryConverter)">
+            Constructor from a table of attributes with ordering.
+            <p>
+            it's is assumed the table contains OID/string pairs, and the contents
+            of the table are copied into an internal table as part of the
+            construction process. The ordering ArrayList should contain the OIDs
+            in the order they are meant to be encoded or printed in ToString.</p>
+            <p>
+            The passed in converter will be used to convert the strings into their
+            ASN.1 counterparts.</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Collections.IList,System.Collections.IList)">
+            Takes two vectors one of the oids and the other of the values.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Collections.IList,System.Collections.IList,Org.BouncyCastle.Asn1.X509.X509NameEntryConverter)">
+            Takes two vectors one of the oids and the other of the values.
+            <p>
+            The passed in converter will be used to convert the strings into their
+            ASN.1 counterparts.</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.String)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.String,Org.BouncyCastle.Asn1.X509.X509NameEntryConverter)">
+            Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+            some such, converting it into an ordered set of name attributes with each
+            string value being converted to its associated ASN.1 type using the passed
+            in converter.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Boolean,System.String)">
+            Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+            some such, converting it into an ordered set of name attributes. If reverse
+            is true, create the encoded version of the sequence starting from the
+            last element in the string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Boolean,System.String,Org.BouncyCastle.Asn1.X509.X509NameEntryConverter)">
+            Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+            some such, converting it into an ordered set of name attributes with each
+            string value being converted to its associated ASN.1 type using the passed
+            in converter. If reverse is true the ASN.1 sequence representing the DN will
+            be built by starting at the end of the string, rather than the start.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Boolean,System.Collections.IDictionary,System.String)">
+            Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+            some such, converting it into an ordered set of name attributes. lookUp
+            should provide a table of lookups, indexed by lowercase only strings and
+            yielding a DerObjectIdentifier, other than that OID. and numeric oids
+            will be processed automatically.
+            <br/>
+            If reverse is true, create the encoded version of the sequence
+            starting from the last element in the string.
+            @param reverse true if we should start scanning from the end (RFC 2553).
+            @param lookUp table of names and their oids.
+            @param dirName the X.500 string to be parsed.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Boolean,System.Collections.IDictionary,System.String,Org.BouncyCastle.Asn1.X509.X509NameEntryConverter)">
+            Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+            some such, converting it into an ordered set of name attributes. lookUp
+            should provide a table of lookups, indexed by lowercase only strings and
+            yielding a DerObjectIdentifier, other than that OID. and numeric oids
+            will be processed automatically. The passed in converter is used to convert the
+            string values to the right of each equals sign to their ASN.1 counterparts.
+            <br/>
+            @param reverse true if we should start scanning from the end, false otherwise.
+            @param lookUp table of names and oids.
+            @param dirName the string dirName
+            @param converter the converter to convert string values into their ASN.1 equivalents
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.GetOidList">
+            return an IList of the oids in the name, in the order they were found.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.GetValueList">
+            return an IList of the values found in the name, in the order they
+            were found.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.GetValueList(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.Equivalent(Org.BouncyCastle.Asn1.X509.X509Name,System.Boolean)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.Equivalent(Org.BouncyCastle.Asn1.X509.X509Name)">
+            test for equivalence - note: case is ignored.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.ToString(System.Boolean,System.Collections.IDictionary)">
+             convert the structure to a string - if reverse is true the
+             oids and values are listed out starting with the last element
+             in the sequence (ala RFC 2253), otherwise the string will begin
+             with the first element of the structure. If no string definition
+             for the oid is found in oidSymbols the string value of the oid is
+             added. Two standard symbol tables are provided DefaultSymbols, and
+             RFC2253Symbols as part of this class.
+            
+             @param reverse if true start at the end of the sequence and work back.
+             @param oidSymbols look up table strings for oids.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.X509Name.DefaultReverse">
+            determines whether or not strings should be processed and printed
+            from back to front.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509NameTokenizer">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.KeySpecificInfo">
+            ASN.1 def for Diffie-Hellman key exchange KeySpecificInfo structure. See
+            RFC 2631, or X9.42, for further details.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.KeySpecificInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             KeySpecificInfo ::= Sequence {
+                 algorithm OBJECT IDENTIFIER,
+                 counter OCTET STRING SIZE (4..4)
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.OtherInfo">
+            ANS.1 def for Diffie-Hellman key exchange OtherInfo structure. See
+            RFC 2631, or X9.42, for further details.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.OtherInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             OtherInfo ::= Sequence {
+                 keyInfo KeySpecificInfo,
+                 partyAInfo [0] OCTET STRING OPTIONAL,
+                 suppPubInfo [2] OCTET STRING
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.X962NamedCurves">
+            table of the current named curves defined in X.962 EC-DSA.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X962NamedCurves.GetByOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X962NamedCurves.GetOid(System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X962NamedCurves.GetName(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            return the named curve name represented by the given object identifier.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X9.X962NamedCurves.Names">
+            returns an enumeration containing the name strings for curves
+            contained in this structure.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X962Parameters.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Parameters ::= CHOICE {
+               ecParameters ECParameters,
+               namedCurve   CURVES.&amp;id({CurveNames}),
+               implicitlyCA Null
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.X9Curve">
+            ASN.1 def for Elliptic-Curve Curve structure. See
+            X9.62, for further details.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9Curve.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             Curve ::= Sequence {
+                 a               FieldElement,
+                 b               FieldElement,
+                 seed            BIT STRING      OPTIONAL
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.X9ECParameters">
+            ASN.1 def for Elliptic-Curve ECParameters structure. See
+            X9.62, for further details.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9ECParameters.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             ECParameters ::= Sequence {
+                 version         Integer { ecpVer1(1) } (ecpVer1),
+                 fieldID         FieldID {{FieldTypes}},
+                 curve           X9Curve,
+                 base            X9ECPoint,
+                 order           Integer,
+                 cofactor        Integer OPTIONAL
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.X9ECPoint">
+            class for describing an ECPoint as a Der object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9ECPoint.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             ECPoint ::= OCTET STRING
+            </pre>
+            <p>
+            Octet string produced using ECPoint.GetEncoded().</p>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.X9FieldElement">
+            Class for processing an ECFieldElement as a DER object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9FieldElement.ToAsn1Object">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.X9FieldID">
+            ASN.1 def for Elliptic-Curve Field ID structure. See
+            X9.62, for further details.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9FieldID.#ctor(Org.BouncyCastle.Math.BigInteger)">
+            Constructor for elliptic curves over prime fields
+            <code>F<sub>2</sub></code>.
+            @param primeP The prime <code>p</code> defining the prime field.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9FieldID.#ctor(System.Int32,System.Int32,System.Int32,System.Int32)">
+            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>..
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9FieldID.ToAsn1Object">
+            Produce a Der encoding of the following structure.
+            <pre>
+             FieldID ::= Sequence {
+                 fieldType       FIELD-ID.&amp;id({IOSet}),
+                 parameters      FIELD-ID.&amp;Type({IOSet}{&#64;fieldType})
+             }
+            </pre>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X9.X9ObjectIdentifiers.AnsiX942">
+            X9.42
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X9.X9ObjectIdentifiers.IdDsaWithSha1">
+            id-dsa-with-sha1 OBJECT IDENTIFIER ::=  { iso(1) member-body(2)
+                  us(840) x9-57 (10040) x9cm(4) 3 }
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X9.X9ObjectIdentifiers.X9x63Scheme">
+            X9.63
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ArmoredInputStream">
+            reader for Base64 armored objects - read the headers and then start returning
+            bytes when the data is reached. An IOException is thrown if the CRC check
+            fails.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.Decode(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32[])">
+             decode the base 64 encoded input data.
+            
+             @return the offset the data starts in out.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.#ctor(System.IO.Stream)">
+             Create a stream for reading a PGP armoured message, parsing up to a header
+             and then reading the data that follows.
+            
+             @param input
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.#ctor(System.IO.Stream,System.Boolean)">
+             Create an armoured input stream which will assume the data starts
+             straight away, or parse for headers first depending on the value of
+             hasHeaders.
+            
+             @param input
+             @param hasHeaders true if headers are to be looked for, false otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.IsClearText">
+            @return true if we are inside the clear text section of a PGP
+            signed message.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.IsEndOfStream">
+            @return true if the stream is actually at end of file.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.GetArmorHeaderLine">
+            Return the armor header line (if there is one)
+            @return the armor header line, null if none present.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.GetArmorHeaders">
+            Return the armor headers (the lines after the armor header line),
+            @return an array of armor headers, null if there aren't any.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ArmoredOutputStream">
+            Basic output stream.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredOutputStream.Encode(System.IO.Stream,System.Int32[],System.Int32)">
+            encode the input data producing a base 64 encoded byte array.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredOutputStream.SetHeader(System.String,System.String)">
+             Set an additional header entry.
+            
+             @param name the name of the header entry.
+             @param v the value of the header entry.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredOutputStream.ResetHeaders">
+            Reset the headers to only contain a Version string.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredOutputStream.BeginClearText(Org.BouncyCastle.Bcpg.HashAlgorithmTag)">
+            Start a clear text signed message.
+            @param hashAlgorithm
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredOutputStream.Dispose(System.Boolean)">
+            <b>Note</b>: Dispose does nor Dispose the underlying stream. So it is possible to write
+            multiple objects using armoring to a single stream.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Attr.ImageAttrib">
+            <remarks>Basic type for a image attribute packet.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.UserAttributeSubpacket">
+            Basic type for a user attribute sub-packet.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.UserAttributeSubpacket.GetData">
+            return the generic data making up the packet.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.BcpgInputStream">
+            <remarks>Reader for PGP objects.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgInputStream.NextPacketTag">
+            <summary>Returns the next packet tag in the stream.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.BcpgInputStream.PartialInputStream">
+            <summary>
+            A stream that overlays our input stream, allowing the user to only read a segment of it.
+            NB: dataLength will be negative if the segment length is in the upper range above 2**31.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.BcpgObject">
+            <remarks>Base class for a PGP object.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.BcpgOutputStream">
+            <remarks>Basic output stream.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.#ctor(System.IO.Stream)">
+            <summary>Create a stream representing a general packet.</summary>
+            <param name="outStr">Output stream to write to.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.#ctor(System.IO.Stream,Org.BouncyCastle.Bcpg.PacketTag)">
+            <summary>Create a stream representing an old style partial object.</summary>
+            <param name="outStr">Output stream to write to.</param>
+            <param name="tag">The packet tag for the object.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.#ctor(System.IO.Stream,Org.BouncyCastle.Bcpg.PacketTag,System.Int64,System.Boolean)">
+            <summary>Create a stream representing a general packet.</summary>
+            <param name="outStr">Output stream to write to.</param>
+            <param name="tag">Packet tag.</param>
+            <param name="length">Size of chunks making up the packet.</param>
+            <param name="oldFormat">If true, the header is written out in old format.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.#ctor(System.IO.Stream,Org.BouncyCastle.Bcpg.PacketTag,System.Int64)">
+            <summary>Create a new style partial input stream buffered into chunks.</summary>
+            <param name="outStr">Output stream to write to.</param>
+            <param name="tag">Packet tag.</param>
+            <param name="length">Size of chunks making up the packet.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.#ctor(System.IO.Stream,Org.BouncyCastle.Bcpg.PacketTag,System.Byte[])">
+            <summary>Create a new style partial input stream buffered into chunks.</summary>
+            <param name="outStr">Output stream to write to.</param>
+            <param name="tag">Packet tag.</param>
+            <param name="buffer">Buffer to use for collecting chunks.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.Flush">
+            <summary>Flush the underlying stream.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.Finish">
+            <summary>Finish writing out the current packet without closing the underlying stream.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.CompressedDataPacket">
+            <remarks>Generic compressed data object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.InputStreamPacket.GetInputStream">
+            <summary>Note: you can only read from this once...</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.CompressedDataPacket.Algorithm">
+            <summary>The algorithm tag value.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.CompressionAlgorithmTag">
+            <remarks>Basic tags for compression algorithms.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ContainedPacket">
+            <remarks>Basic type for a PGP packet.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.DsaPublicBcpgKey">
+            <remarks>Base class for a DSA public key.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.IBcpgKey">
+            <remarks>Base interface for a PGP key.</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.IBcpgKey.Format">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.DsaPublicBcpgKey.#ctor(Org.BouncyCastle.Bcpg.BcpgInputStream)">
+            <param name="bcpgIn">The stream to read the packet from.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.DsaPublicBcpgKey.GetEncoded">
+            <summary>Return the standard PGP encoding of the key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.DsaPublicBcpgKey.Format">
+            <summary>The format, as a string, always "PGP".</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.DsaSecretBcpgKey">
+            <remarks>Base class for a DSA secret key.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.DsaSecretBcpgKey.#ctor(Org.BouncyCastle.Bcpg.BcpgInputStream)">
+            @param in
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.DsaSecretBcpgKey.GetEncoded">
+            <summary>Return the standard PGP encoding of the key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.DsaSecretBcpgKey.Format">
+            <summary>The format, as a string, always "PGP".</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.DsaSecretBcpgKey.X">
+            @return x
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ElGamalPublicBcpgKey">
+            <remarks>Base class for an ElGamal public key.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ElGamalPublicBcpgKey.GetEncoded">
+            <summary>Return the standard PGP encoding of the key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.ElGamalPublicBcpgKey.Format">
+            <summary>The format, as a string, always "PGP".</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ElGamalSecretBcpgKey">
+            <remarks>Base class for an ElGamal secret key.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ElGamalSecretBcpgKey.#ctor(Org.BouncyCastle.Bcpg.BcpgInputStream)">
+            @param in
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ElGamalSecretBcpgKey.#ctor(Org.BouncyCastle.Math.BigInteger)">
+            @param x
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ElGamalSecretBcpgKey.GetEncoded">
+            <summary>Return the standard PGP encoding of the key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.ElGamalSecretBcpgKey.Format">
+            <summary>The format, as a string, always "PGP".</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ExperimentalPacket">
+            <remarks>Basic packet for an experimental packet.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.HashAlgorithmTag">
+            <remarks>Basic tags for hash algorithms.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.LiteralDataPacket">
+            <remarks>Generic literal data packet.</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.LiteralDataPacket.Format">
+            <summary>The format tag value.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.LiteralDataPacket.ModificationTime">
+            <summary>The modification time of the file in milli-seconds (since Jan 1, 1970 UTC)</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.MarkerPacket">
+            <remarks>Basic type for a marker packet.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ModDetectionCodePacket">
+            <remarks>Basic packet for a modification detection code packet.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.MPInteger">
+            <remarks>A multiple precision integer</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OnePassSignaturePacket">
+            <remarks>Generic signature object</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OnePassSignaturePacket.KeyAlgorithm">
+            <summary>The encryption algorithm tag.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OnePassSignaturePacket.HashAlgorithm">
+            <summary>The hash algorithm tag.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.PacketTag">
+            <remarks>Basic PGP packet tag types.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag">
+            <remarks>Public Key Algorithm tag numbers.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.PublicKeyEncSessionPacket">
+            <remarks>Basic packet for a PGP public key.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.PublicKeyPacket">
+            <remarks>Basic packet for a PGP public key.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.PublicKeyPacket.#ctor(Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,System.DateTime,Org.BouncyCastle.Bcpg.IBcpgKey)">
+            <summary>Construct a version 4 public key packet.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.PublicSubkeyPacket">
+            <remarks>Basic packet for a PGP public subkey</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.PublicSubkeyPacket.#ctor(Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,System.DateTime,Org.BouncyCastle.Bcpg.IBcpgKey)">
+            <summary>Construct a version 4 public subkey packet.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.RsaPublicBcpgKey">
+            <remarks>Base class for an RSA public key.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.RsaPublicBcpgKey.#ctor(Org.BouncyCastle.Bcpg.BcpgInputStream)">
+            <summary>Construct an RSA public key from the passed in stream.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.RsaPublicBcpgKey.#ctor(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            <param name="n">The modulus.</param>
+            <param name="e">The public exponent.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.RsaPublicBcpgKey.GetEncoded">
+            <summary>Return the standard PGP encoding of the key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.RsaPublicBcpgKey.Format">
+            <summary>The format, as a string, always "PGP".</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.RsaSecretBcpgKey">
+            <remarks>Base class for an RSA secret (or priate) key.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.RsaSecretBcpgKey.GetEncoded">
+            <summary>Return the standard PGP encoding of the key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.RsaSecretBcpgKey.Format">
+            <summary>The format, as a string, always "PGP".</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.S2k">
+            <remarks>The string to key specifier class.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.S2k.GetIV">
+            <summary>The IV for the key generation algorithm.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.S2k.HashAlgorithm">
+            <summary>The hash algorithm.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.S2k.IterationCount">
+            <summary>The iteration count</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.S2k.ProtectionMode">
+            <summary>The protection mode - only if GnuDummyS2K</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SecretKeyPacket">
+            <remarks>Basic packet for a PGP secret key.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SecretSubkeyPacket">
+            <remarks>Basic packet for a PGP secret key.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SignaturePacket">
+            <remarks>Generic signature packet.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SignaturePacket.#ctor(System.Int32,System.Int64,Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,Org.BouncyCastle.Bcpg.HashAlgorithmTag,Org.BouncyCastle.Bcpg.SignatureSubpacket[],Org.BouncyCastle.Bcpg.SignatureSubpacket[],System.Byte[],Org.BouncyCastle.Bcpg.MPInteger[])">
+             Generate a version 4 signature packet.
+            
+             @param signatureType
+             @param keyAlgorithm
+             @param hashAlgorithm
+             @param hashedData
+             @param unhashedData
+             @param fingerprint
+             @param signature
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SignaturePacket.#ctor(System.Int32,System.Int32,System.Int64,Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,Org.BouncyCastle.Bcpg.HashAlgorithmTag,System.Int64,System.Byte[],Org.BouncyCastle.Bcpg.MPInteger[])">
+             Generate a version 2/3 signature packet.
+            
+             @param signatureType
+             @param keyAlgorithm
+             @param hashAlgorithm
+             @param fingerprint
+             @param signature
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SignaturePacket.GetSignatureTrailer">
+             return the signature trailer that must be included with the data
+             to reconstruct the signature
+            
+             @return byte[]
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SignaturePacket.GetSignature">
+            		* 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SignaturePacket.GetSignatureBytes">
+            Return the byte encoding of the signature section.
+            @return uninterpreted signature bytes.
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.SignaturePacket.KeyId">
+            return the keyId
+            @return the keyId that created the signature.
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.SignaturePacket.CreationTime">
+            <summary>Return the creation time in milliseconds since 1 Jan., 1970 UTC.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SignatureSubpacket">
+            <remarks>Basic type for a PGP Signature sub-packet.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SignatureSubpacket.GetData">
+            <summary>Return the generic data making up the packet.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SignatureSubpacketsParser">
+            reader for signature sub-packets
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SignatureSubpacketTag">
+            Basic PGP signature sub-packet tag types.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.EmbeddedSignature">
+            Packet embedded signature
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.Exportable">
+            packet giving signature creation time.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.IssuerKeyId">
+            packet giving signature creation time.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.KeyExpirationTime">
+            packet giving time after creation at which the key expires.
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.Sig.KeyExpirationTime.Time">
+             Return the number of seconds after creation time a key is valid for.
+            
+             @return second count for key validity.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.KeyFlags">
+            Packet holding the key flag values.
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.Sig.KeyFlags.Flags">
+            <summary>
+            Return the flag values contained in the first 4 octets (note: at the moment
+            the standard only uses the first one).
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.NotationData">
+            Class provided a NotationData object according to
+            RFC2440, Chapter 5.2.3.15. Notation Data
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.PreferredAlgorithms">
+            packet giving signature creation time.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.PrimaryUserId">
+            packet giving whether or not the signature is signed using the primary user ID for the key.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.Revocable">
+            packet giving whether or not is revocable.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.RevocationKey">
+            <summary>
+            Represents revocation key OpenPGP signature sub packet.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.RevocationReason">
+            <summary>
+            Represents revocation reason OpenPGP signature sub packet.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.SignatureCreationTime">
+            packet giving signature creation time.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.SignatureExpirationTime">
+            packet giving signature expiration time.
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.Sig.SignatureExpirationTime.Time">
+            return time in seconds before signature expires after creation time.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.SignerUserId">
+            packet giving the User ID of the signer.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.TrustSignature">
+            packet giving trust.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SymmetricEncDataPacket">
+            <remarks>Basic type for a symmetric key encrypted packet.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag">
+            Basic tags for symmetric key algorithms
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SymmetricKeyEncSessionPacket">
+            Basic type for a symmetric encrypted session key packet
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SymmetricKeyEncSessionPacket.GetSecKeyData">
+            @return byte[]
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.SymmetricKeyEncSessionPacket.EncAlgorithm">
+            @return int
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.SymmetricKeyEncSessionPacket.S2k">
+            @return S2k
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.SymmetricKeyEncSessionPacket.Version">
+            @return int
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.TrustPacket">
+            <summary>Basic type for a trust packet.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.UserAttributePacket">
+            Basic type for a user attribute packet.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.UserAttributeSubpacketsParser">
+            reader for user attribute sub-packets
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.UserAttributeSubpacketTag">
+            Basic PGP user attribute sub-packet tag types.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.UserIdPacket">
+            Basic type for a user ID packet.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsAttributeTableParameter">
+            <remarks>
+            The 'Signature' parameter is only available when generating unsigned attributes.
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsAuthenticatedData">
+            containing class for an CMS Authenticated Data object
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedData.GetRecipientInfos">
+            return a store of the intended recipients for this message
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedData.GetAuthAttrs">
+            return a table of the digested attributes indexed by
+            the OID of the attribute.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedData.GetUnauthAttrs">
+            return a table of the undigested attributes indexed by
+            the OID of the attribute.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedData.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsAuthenticatedData.MacAlgOid">
+            return the object identifier for the content MAC algorithm.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsAuthenticatedData.ContentInfo">
+            return the ContentInfo 
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsAuthenticatedDataGenerator">
+             General class for generating a CMS authenticated-data message.
+            
+             A simple example of usage.
+            
+             <pre>
+                  CMSAuthenticatedDataGenerator  fact = new CMSAuthenticatedDataGenerator();
+            
+                  fact.addKeyTransRecipient(cert);
+            
+                  CMSAuthenticatedData         data = fact.generate(content, algorithm, "BC");
+             </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsEnvelopedGenerator">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Constructor allowing specific source of randomness</summary>
+            <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.AddKeyTransRecipient(Org.BouncyCastle.X509.X509Certificate)">
+             add a recipient.
+            
+             @param cert recipient's public key certificate
+             @exception ArgumentException if there is a problem with the certificate
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.AddKeyTransRecipient(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[])">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.AddKekRecipient(System.String,Org.BouncyCastle.Crypto.Parameters.KeyParameter,System.Byte[])">
+            add a KEK recipient.
+            @param key the secret key to use for wrapping
+            @param keyIdentifier the byte string that identifies the key
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.AddKekRecipient(System.String,Org.BouncyCastle.Crypto.Parameters.KeyParameter,Org.BouncyCastle.Asn1.Cms.KekIdentifier)">
+            add a KEK recipient.
+            @param key the secret key to use for wrapping
+            @param keyIdentifier the byte string that identifies the key
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.AddKeyAgreementRecipient(System.String,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.AddKeyAgreementRecipients(System.String,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Collections.ICollection,System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedGenerator.#ctor">
+            base constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+             constructor allowing specific source of randomness
+            
+             @param rand instance of SecureRandom to use
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataGenerator.#ctor">
+            base constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            constructor allowing specific source of randomness
+            @param rand instance of SecureRandom to use
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.String,Org.BouncyCastle.Crypto.CipherKeyGenerator)">
+            generate an enveloped object that contains an CMS Enveloped Data
+            object using the given provider and the passed in key generator.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.String)">
+            generate an authenticated object that contains an CMS Authenticated Data object
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsAuthenticatedDataParser">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsContentInfoParser.Close">
+            Close the underlying data stream.
+            @throws IOException if the close fails.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataParser.GetRecipientInfos">
+            return a store of the intended recipients for this message
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataParser.GetAuthAttrs">
+            return a table of the unauthenticated attributes indexed by
+            the OID of the attribute.
+            @exception java.io.IOException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataParser.GetUnauthAttrs">
+            return a table of the unauthenticated attributes indexed by
+            the OID of the attribute.
+            @exception java.io.IOException
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsAuthenticatedDataParser.MacAlgOid">
+            return the object identifier for the mac algorithm.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsAuthenticatedDataParser.MacAlgParams">
+            return the ASN.1 encoded encryption algorithm parameters, or null if
+            there aren't any.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator">
+             General class for generating a CMS authenticated-data message stream.
+             <p>
+             A simple example of usage.
+             <pre>
+                  CMSAuthenticatedDataStreamGenerator edGen = new CMSAuthenticatedDataStreamGenerator();
+            
+                  edGen.addKeyTransRecipient(cert);
+            
+                  ByteArrayOutputStream  bOut = new ByteArrayOutputStream();
+            
+                  OutputStream out = edGen.open(
+                                          bOut, CMSAuthenticatedDataGenerator.AES128_CBC, "BC");*
+                  out.write(data);
+            
+                  out.close();
+             </pre>
+             </p>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.#ctor">
+            base constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            constructor allowing specific source of randomness
+            @param rand instance of SecureRandom to use
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.SetBufferSize(System.Int32)">
+             Set the underlying string size for encapsulated data
+            
+             @param bufferSize length of octet strings to buffer the data.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.SetBerEncodeRecipients(System.Boolean)">
+            Use a BER Set to store the recipient information
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.Open(System.IO.Stream,System.String,Org.BouncyCastle.Crypto.CipherKeyGenerator)">
+            generate an enveloped object that contains an CMS Enveloped Data
+            object using the given provider and the passed in key generator.
+            @throws java.io.IOException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.Open(System.IO.Stream,System.String)">
+            generate an enveloped object that contains an CMS Enveloped Data object
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.Open(System.IO.Stream,System.String,System.Int32)">
+            generate an enveloped object that contains an CMS Enveloped Data object
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsAuthEnvelopedData">
+            containing class for an CMS AuthEnveloped Data object
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsCompressedData">
+            containing class for an CMS Compressed Data object
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsCompressedData.GetContent">
+             Return the uncompressed content.
+            
+             @return the uncompressed content
+             @throws CmsException if there is an exception uncompressing the data.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsCompressedData.GetContent(System.Int32)">
+             Return the uncompressed content, throwing an exception if the data size
+             is greater than the passed in limit. If the content is exceeded getCause()
+             on the CMSException will contain a StreamOverflowException
+            
+             @param limit maximum number of bytes to read
+             @return the content read
+             @throws CMSException if there is an exception uncompressing the data.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsCompressedData.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsCompressedData.ContentInfo">
+            return the ContentInfo 
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsCompressedDataGenerator">
+                * General class for generating a compressed CMS message.
+                * <p>
+                * A simple example of usage.</p>
+                * <p>
+                * <pre>
+                *      CMSCompressedDataGenerator fact = new CMSCompressedDataGenerator();
+                *      CMSCompressedData data = fact.Generate(content, algorithm);
+                * </pre>
+            	* </p>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsCompressedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.String)">
+            Generate an object that contains an CMS Compressed Data
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsCompressedDataParser">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsCompressedDataStreamGenerator">
+             General class for generating a compressed CMS message stream.
+             <p>
+             A simple example of usage.
+             </p>
+             <pre>
+                  CMSCompressedDataStreamGenerator gen = new CMSCompressedDataStreamGenerator();
+            
+                  Stream cOut = gen.Open(outputStream, CMSCompressedDataStreamGenerator.ZLIB);
+            
+                  cOut.Write(data);
+            
+                  cOut.Close();
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsCompressedDataStreamGenerator.#ctor">
+            base constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsCompressedDataStreamGenerator.SetBufferSize(System.Int32)">
+             Set the underlying string size for encapsulated data
+            
+             @param bufferSize length of octet strings to buffer the data.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsEnvelopedData">
+            containing class for an CMS Enveloped Data object
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedData.GetRecipientInfos">
+            return a store of the intended recipients for this message
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedData.GetUnprotectedAttributes">
+            return a table of the unprotected attributes indexed by
+            the OID of the attribute.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedData.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsEnvelopedData.EncryptionAlgOid">
+            return the object identifier for the content encryption algorithm.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsEnvelopedData.ContentInfo">
+            return the ContentInfo 
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsEnvelopedDataGenerator">
+             <remarks>
+             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);
+             </pre>
+             </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Constructor allowing specific source of randomness</summary>
+            <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.String,Org.BouncyCastle.Crypto.CipherKeyGenerator)">
+            <summary>
+            Generate an enveloped object that contains a CMS Enveloped Data
+            object using the passed in key generator.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.String)">
+            <summary>Generate an enveloped object that contains an CMS Enveloped Data object.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.String,System.Int32)">
+            <summary>Generate an enveloped object that contains an CMS Enveloped Data object.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsEnvelopedDataParser">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataParser.GetRecipientInfos">
+            return a store of the intended recipients for this message
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataParser.GetUnprotectedAttributes">
+            return a table of the unprotected attributes indexed by
+            the OID of the attribute.
+            @throws IOException
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsEnvelopedDataParser.EncryptionAlgOid">
+            return the object identifier for the content encryption algorithm.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsEnvelopedDataParser.EncryptionAlgParams">
+            return the ASN.1 encoded encryption algorithm parameters, or null if
+            there aren't any.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator">
+             General class for generating a CMS enveloped-data message stream.
+             <p>
+             A simple example of usage.
+             <pre>
+                  CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
+            
+                  edGen.AddKeyTransRecipient(cert);
+            
+                  MemoryStream  bOut = new MemoryStream();
+            
+                  Stream out = edGen.Open(
+                                          bOut, CMSEnvelopedDataGenerator.AES128_CBC);*
+                  out.Write(data);
+            
+                  out.Close();
+             </pre>
+             </p>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Constructor allowing specific source of randomness</summary>
+            <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator.SetBufferSize(System.Int32)">
+            <summary>Set the underlying string size for encapsulated data.</summary>
+            <param name="bufferSize">Length of octet strings to buffer the data.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator.SetBerEncodeRecipients(System.Boolean)">
+            <summary>Use a BER Set to store the recipient information.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator.Open(System.IO.Stream,System.String,Org.BouncyCastle.Crypto.CipherKeyGenerator)">
+            <summary>
+            Generate an enveloped object that contains an CMS Enveloped Data
+            object using the passed in key generator.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator.Open(System.IO.Stream,System.String)">
+            generate an enveloped object that contains an CMS Enveloped Data object
+            @throws IOException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator.Open(System.IO.Stream,System.String,System.Int32)">
+            generate an enveloped object that contains an CMS Enveloped Data object
+            @throws IOException
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.ICipherParameters">
+            all parameter classes implement this.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsProcessable.Write(System.IO.Stream)">
+            <summary>
+            Generic routine to copy out the data we want processed.
+            </summary>
+            <remarks>
+            This routine may be called multiple times.
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsProcessableByteArray">
+            a holding class for a byte array of data to be processed.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsProcessableByteArray.GetContent">
+            <returns>A clone of the byte array</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsSignedData">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.#ctor(System.Collections.IDictionary,System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.#ctor(Org.BouncyCastle.Cms.CmsProcessable,System.IO.Stream)">
+             base constructor - content with detached signature.
+            
+             @param signedContent the content that was signed.
+             @param sigData the signature object.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.#ctor(System.IO.Stream)">
+            base constructor - with encapsulated content
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.GetSignerInfos">
+            return the collection of signers that are associated with the
+            signatures for the message.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.GetAttributeCertificates(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.GetCertificates(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.GetCrls(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.ReplaceSigners(Org.BouncyCastle.Cms.CmsSignedData,Org.BouncyCastle.Cms.SignerInformationStore)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.ReplaceCertificatesAndCrls(Org.BouncyCastle.Cms.CmsSignedData,Org.BouncyCastle.X509.Store.IX509Store,Org.BouncyCastle.X509.Store.IX509Store,Org.BouncyCastle.X509.Store.IX509Store)">
+             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
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsSignedData.Version">
+            <summary>Return the version number for this object.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsSignedData.SignedContentType">
+            <summary>
+            Return the <c>DerObjectIdentifier</c> associated with the encapsulated
+            content info structure carried in the signed data.
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsSignedData.ContentInfo">
+            return the ContentInfo
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsSignedDataGenerator">
+                 * general class for generating a pkcs7-signature message.
+                 * <p>
+                 * A simple example of usage.
+                 *
+                 * <pre>
+                 *      IX509Store certs...
+                 *      IX509Store crls...
+                 *      CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+                 *
+                 *      gen.AddSigner(privKey, cert, CmsSignedGenerator.DigestSha1);
+                 *      gen.AddCertificates(certs);
+                 *      gen.AddCrls(crls);
+                 *
+                 *      CmsSignedData data = gen.Generate(content);
+                 * </pre>
+            	 * </p>
+        </member>
+        <member name="F:Org.BouncyCastle.Cms.CmsSignedGenerator.Data">
+            Default type for the signed data.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Constructor allowing specific source of randomness</summary>
+            <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedGenerator.AddAttributeCertificates(Org.BouncyCastle.X509.Store.IX509Store)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedGenerator.AddSigners(Org.BouncyCastle.Cms.SignerInformationStore)">
+             Add a store of precalculated signers to the generator.
+            
+             @param signerStore store of signers
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedGenerator.GetGeneratedDigests">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Constructor allowing specific source of randomness</summary>
+            <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String)">
+                    * add a signer - no attributes other than the default ones will be
+                    * provided here.
+            		*
+            		* @param key signing key to use
+            		* @param cert certificate containing corresponding public key
+            		* @param digestOID digest algorithm OID
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String)">
+             add a signer, specifying the digest encryption algorithm to use - no attributes other than the default ones will be
+             provided here.
+            
+             @param key signing key to use
+             @param cert certificate containing corresponding public key
+             @param encryptionOID digest encryption algorithm OID
+             @param digestOID digest algorithm OID
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String)">
+            add a signer - no attributes other than the default ones will be
+            provided here.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,System.String)">
+            add a signer, specifying the digest encryption algorithm to use - no attributes other than the default ones will be
+            provided here.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+                    * add a signer with extra signed/unsigned attributes.
+            		*
+            		* @param key signing key to use
+            		* @param cert certificate containing corresponding public key
+            		* @param digestOID digest algorithm OID
+            		* @param signedAttr table of attributes to be included in signature
+            		* @param unsignedAttr table of attributes to be included as unsigned
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+             add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes.
+            
+             @param key signing key to use
+             @param cert certificate containing corresponding public key
+             @param encryptionOID digest encryption algorithm OID
+             @param digestOID digest algorithm OID
+             @param signedAttr table of attributes to be included in signature
+             @param unsignedAttr table of attributes to be included as unsigned
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+            	     * add a signer with extra signed/unsigned attributes.
+            		 *
+            		 * @param key signing key to use
+            		 * @param subjectKeyID subjectKeyID of corresponding public key
+            		 * @param digestOID digest algorithm OID
+            		 * @param signedAttr table of attributes to be included in signature
+            		 * @param unsignedAttr table of attributes to be included as unsigned
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+             add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes.
+            
+             @param key signing key to use
+             @param subjectKeyID subjectKeyID of corresponding public key
+             @param encryptionOID digest encryption algorithm OID
+             @param digestOID digest algorithm OID
+             @param signedAttr table of attributes to be included in signature
+             @param unsignedAttr table of attributes to be included as unsigned
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,Org.BouncyCastle.Cms.CmsAttributeTableGenerator,Org.BouncyCastle.Cms.CmsAttributeTableGenerator)">
+            add a signer with extra signed/unsigned attributes based on generators.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String,Org.BouncyCastle.Cms.CmsAttributeTableGenerator,Org.BouncyCastle.Cms.CmsAttributeTableGenerator)">
+            add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes based on generators.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,Org.BouncyCastle.Cms.CmsAttributeTableGenerator,Org.BouncyCastle.Cms.CmsAttributeTableGenerator)">
+            add a signer with extra signed/unsigned attributes based on generators.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,System.String,Org.BouncyCastle.Cms.CmsAttributeTableGenerator,Org.BouncyCastle.Cms.CmsAttributeTableGenerator)">
+            add a signer, including digest encryption algorithm, with extra signed/unsigned attributes based on generators.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable)">
+            generate a signed object that for a CMS Signed Data object
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.Generate(System.String,Org.BouncyCastle.Cms.CmsProcessable,System.Boolean)">
+            generate a signed object that for a CMS Signed Data
+            object  - if encapsulate is true a copy
+            of the message will be included in the signature. The content type
+            is set according to the OID represented by the string signedContentType.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.Boolean)">
+            generate a signed object that for a CMS Signed Data
+            object - if encapsulate is true a copy
+            of the message will be included in the signature with the
+            default content type "data".
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.GenerateCounterSigners(Org.BouncyCastle.Cms.SignerInformation)">
+             generate a set of one or more SignerInformation objects representing counter signatures on
+             the passed in SignerInformation object.
+            
+             @param signer the signer to be countersigned
+             @param sigProvider the provider to be used for counter signing.
+             @return a store containing the signers.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsSignedDataParser">
+             Parsing class for an CMS Signed Data object from an input stream.
+             <p>
+             Note: that because we are in a streaming mode only one signer can be tried and it is important
+             that the methods on the parser are called in the appropriate order.
+             </p>
+             <p>
+             A simple example of usage for an encapsulated signature.
+             </p>
+             <p>
+             Two notes: first, in the example below the validity of
+             the certificate isn't verified, just the fact that one of the certs
+             matches the given signer, and, second, because we are in a streaming
+             mode the order of the operations is important.
+             </p>
+             <pre>
+                  CmsSignedDataParser     sp = new CmsSignedDataParser(encapSigData);
+            
+                  sp.GetSignedContent().Drain();
+            
+                  IX509Store              certs = sp.GetCertificates();
+                  SignerInformationStore  signers = sp.GetSignerInfos();
+            
+                  foreach (SignerInformation signer in signers.GetSigners())
+                  {
+                      ArrayList       certList = new ArrayList(certs.GetMatches(signer.SignerID));
+                      X509Certificate cert = (X509Certificate) certList[0];
+            
+                      Console.WriteLine("verify returns: " + signer.Verify(cert));
+                  }
+             </pre>
+              Note also: this class does not introduce buffering - if you are processing large files you should create
+              the parser with:
+              <pre>
+                      CmsSignedDataParser     ep = new CmsSignedDataParser(new BufferedInputStream(encapSigData, bufSize));
+              </pre>
+              where bufSize is a suitably large buffer size.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.#ctor(System.IO.Stream)">
+            base constructor - with encapsulated content
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.#ctor(Org.BouncyCastle.Cms.CmsTypedStream,System.IO.Stream)">
+             base constructor
+            
+             @param signedContent the content that was signed.
+             @param sigData the signature object.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.GetSignerInfos">
+            return the collection of signers that are associated with the
+            signatures for the message.
+            @throws CmsException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.GetAttributeCertificates(System.String)">
+             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 org.bouncycastle.x509.NoSuchStoreException if the store type isn't available.
+             @exception CmsException if a general exception prevents creation of the X509Store
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.GetCertificates(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.GetCrls(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.ReplaceSigners(System.IO.Stream,Org.BouncyCastle.Cms.SignerInformationStore,System.IO.Stream)">
+            Replace the signerinformation store associated with the passed
+            in message contained in the stream original 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.
+            <p>
+            The output stream is returned unclosed.
+            </p>
+            @param original the signed data stream to be used as a base.
+            @param signerInformationStore the new signer information store to use.
+            @param out the stream to Write the new signed data object to.
+            @return out.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.ReplaceCertificatesAndCrls(System.IO.Stream,Org.BouncyCastle.X509.Store.IX509Store,Org.BouncyCastle.X509.Store.IX509Store,Org.BouncyCastle.X509.Store.IX509Store,System.IO.Stream)">
+            Replace the certificate and CRL information associated with this
+            CMSSignedData object with the new one passed in.
+            <p>
+            The output stream is returned unclosed.
+            </p>
+            @param original the signed data stream to be used as a base.
+            @param certsAndCrls the new certificates and CRLs to be used.
+            @param out the stream to Write the new signed data object to.
+            @return out.
+            @exception CmsException if there is an error processing the CertStore
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsSignedDataParser.Version">
+             Return the version number for the SignedData object
+            
+             @return the version number
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsSignedDataParser.SignedContentType">
+            <summary>
+            Return the <c>DerObjectIdentifier</c> associated with the encapsulated
+            content info structure carried in the signed data.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator">
+             General class for generating a pkcs7-signature message stream.
+             <p>
+             A simple example of usage.
+             </p>
+             <pre>
+                  IX509Store                   certs...
+                  CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+            
+                  gen.AddSigner(privateKey, cert, CmsSignedDataStreamGenerator.DIGEST_SHA1);
+            
+                  gen.AddCertificates(certs);
+            
+                  Stream sigOut = gen.Open(bOut);
+            
+                  sigOut.Write(Encoding.UTF8.GetBytes("Hello World!"));
+            
+                  sigOut.Close();
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Constructor allowing specific source of randomness</summary>
+            <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.SetBufferSize(System.Int32)">
+             Set the underlying string size for encapsulated data
+            
+             @param bufferSize length of octet strings to buffer the data.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String)">
+            add a signer - no attributes other than the default ones will be
+            provided here.
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String)">
+            add a signer, specifying the digest encryption algorithm - no attributes other than the default ones will be
+            provided here.
+            @throws NoSuchProviderException
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+            add a signer with extra signed/unsigned attributes.
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+            add a signer with extra signed/unsigned attributes - specifying digest
+            encryption algorithm.
+            @throws NoSuchProviderException
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String)">
+            add a signer - no attributes other than the default ones will be
+            provided here.
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,System.String)">
+            add a signer - no attributes other than the default ones will be
+            provided here.
+            @throws NoSuchProviderException
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+            add a signer with extra signed/unsigned attributes.
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.Open(System.IO.Stream)">
+            generate a signed object that for a CMS Signed Data object
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.Open(System.IO.Stream,System.Boolean)">
+            generate a signed object that for a CMS Signed Data
+            object - if encapsulate is true a copy
+            of the message will be included in the signature with the
+            default content type "data".
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.Open(System.IO.Stream,System.Boolean,System.IO.Stream)">
+            generate a signed object that for a CMS Signed Data
+            object using the given provider - if encapsulate is true a copy
+            of the message will be included in the signature with the
+            default content type "data". If dataOutputStream is non null the data
+            being signed will be written to the stream as it is processed.
+            @param out stream the CMS object is to be written to.
+            @param encapsulate true if data should be encapsulated.
+            @param dataOutputStream output stream to copy the data being signed to.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.Open(System.IO.Stream,System.String,System.Boolean)">
+            generate a signed object that for a CMS Signed Data
+            object - if encapsulate is true a copy
+            of the message will be included in the signature. The content type
+            is set according to the OID represented by the string signedContentType.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.Open(System.IO.Stream,System.String,System.Boolean,System.IO.Stream)">
+            generate a signed object that for a CMS Signed Data
+            object using the given provider - if encapsulate is true a copy
+            of the message will be included in the signature. The content type
+            is set according to the OID represented by the string signedContentType.
+            @param out stream the CMS object is to be written to.
+            @param signedContentType OID for data to be signed.
+            @param encapsulate true if data should be encapsulated.
+            @param dataOutputStream output stream to copy the data being signed to.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedHelper.GetDigestAlgName(System.String)">
+            Return the digest algorithm using one of the standard JCA string
+            representations rather than the algorithm identifier (if possible).
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedHelper.GetEncryptionAlgName(System.String)">
+            Return the digest encryption algorithm using one of the standard
+            JCA string representations rather than the algorithm identifier (if
+            possible).
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.DefaultAuthenticatedAttributeTableGenerator">
+            Default authenticated attributes generator.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultAuthenticatedAttributeTableGenerator.#ctor">
+            Initialise to use all defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultAuthenticatedAttributeTableGenerator.#ctor(Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+             Initialise with some extra attributes or overrides.
+            
+             @param attributeTable initial attribute table to use.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultAuthenticatedAttributeTableGenerator.CreateStandardAttributeTable(System.Collections.IDictionary)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultAuthenticatedAttributeTableGenerator.GetAttributes(System.Collections.IDictionary)">
+            @param parameters source parameters
+            @return the populated attribute table
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.DefaultSignedAttributeTableGenerator">
+            Default signed attributes generator.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultSignedAttributeTableGenerator.#ctor">
+            Initialise to use all defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultSignedAttributeTableGenerator.#ctor(Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+             Initialise with some extra attributes or overrides.
+            
+             @param attributeTable initial attribute table to use.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultSignedAttributeTableGenerator.createStandardAttributeTable(System.Collections.IDictionary)">
+             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
+             messageDigest will override the generated ones.
+            
+             @param parameters source parameters for table generation.
+            
+             @return a filled in Hashtable of attributes.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultSignedAttributeTableGenerator.GetAttributes(System.Collections.IDictionary)">
+            @param parameters source parameters
+            @return the populated attribute table
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.RecipientInfoGenerator.Generate(Org.BouncyCastle.Crypto.Parameters.KeyParameter,Org.BouncyCastle.Security.SecureRandom)">
+            <summary>
+            Generate a RecipientInfo object for the given key.
+            </summary>
+            <param name="contentEncryptionKey">
+            A <see cref="T:Org.BouncyCastle.Crypto.Parameters.KeyParameter"/>
+            </param>
+            <param name="random">
+            A <see cref="T:Org.BouncyCastle.Security.SecureRandom"/>
+            </param>
+            <returns>
+            A <see cref="T:Org.BouncyCastle.Asn1.Cms.RecipientInfo"/>
+            </returns>
+            <exception cref="T:Org.BouncyCastle.Security.GeneralSecurityException"></exception>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.KekRecipientInformation">
+            the RecipientInfo class for a recipient who has been sent a message
+            encrypted using a secret key known to the other side.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.RecipientInformation.GetMac">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.RecipientInformation.KeyEncryptionAlgOid">
+                    * return the object identifier for the key encryption algorithm.
+                    * 
+            		* @return OID for key encryption algorithm.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.RecipientInformation.KeyEncryptionAlgParams">
+                    * 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.KekRecipientInformation.GetContentStream(Org.BouncyCastle.Crypto.ICipherParameters)">
+            decrypt the content and return an input stream.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.KeyAgreeRecipientInformation">
+            the RecipientInfo class for a recipient who has been sent a message
+            encrypted using key agreement.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.KeyAgreeRecipientInformation.GetContentStream(Org.BouncyCastle.Crypto.ICipherParameters)">
+            decrypt the content and return an input stream.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.KeyTransRecipientInformation">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.KeyTransRecipientInformation.GetContentStream(Org.BouncyCastle.Crypto.ICipherParameters)">
+            decrypt the content and return it as a byte array.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.OriginatorID">
+            a basic index for an originator.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CertStoreSelector.Policy">
+            <summary>
+            An <code>ISet</code> of <code>DerObjectIdentifier</code> objects.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.PasswordRecipientInformation">
+            the RecipientInfo class for a recipient who has been sent a message
+            encrypted using a password.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.PasswordRecipientInformation.GetContentStream(Org.BouncyCastle.Crypto.ICipherParameters)">
+            decrypt the content and return an input stream.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.PasswordRecipientInformation.KeyDerivationAlgorithm">
+             return the object identifier for the key derivation algorithm, or null
+             if there is none present.
+            
+             @return OID for key derivation algorithm, if present.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.Pkcs5Scheme2PbeKey">
+            <summary>
+            PKCS5 scheme-2 - password converted to bytes assuming ASCII.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.Pkcs5Scheme2Utf8PbeKey">
+            PKCS5 scheme-2 - password converted to bytes using UTF-8.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.RecipientInformationStore.GetFirstRecipient(Org.BouncyCastle.Cms.RecipientID)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.RecipientInformationStore.GetRecipients">
+             Return all recipients in the collection
+            
+             @return a collection of recipients.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.RecipientInformationStore.GetRecipients(Org.BouncyCastle.Cms.RecipientID)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.RecipientInformationStore.Count">
+             Return the number of recipients in the collection.
+            
+             @return number of recipients identified.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.SignerID">
+            a basic index for a signer.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.SignerInformation">
+            an expanded SignerInfo block from a CMS Signed message
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.GetContentDigest">
+            return the content digest that was calculated during verification.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.GetSignature">
+            return the encoded signature
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.GetCounterSignatures">
+            Return a SignerInformationStore containing the counter signatures attached to this
+            signer. If no counter signatures are present an empty store is returned.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.GetEncodedSignedAttributes">
+            return the DER encoding of the signed attributes.
+            @throws IOException if an encoding error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.Verify(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            verify that the given public key successfully handles and confirms the
+            signature associated with this signer.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.Verify(Org.BouncyCastle.X509.X509Certificate)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.ToSignerInfo">
+             Return the base ASN.1 CMS structure that this object contains.
+            
+             @return an object containing a CMS SignerInfo structure.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.ReplaceUnsignedAttributes(Org.BouncyCastle.Cms.SignerInformation,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.AddCounterSigners(Org.BouncyCastle.Cms.SignerInformation,Org.BouncyCastle.Cms.SignerInformationStore)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.Version">
+            return the version number for this objects underlying SignerInfo structure.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.DigestAlgOid">
+            return the object identifier for the signature.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.DigestAlgParams">
+            return the signature parameters, or null if there aren't any.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.EncryptionAlgOid">
+            return the object identifier for the signature.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.EncryptionAlgParams">
+            return the signature/encryption algorithm parameters, or null if
+            there aren't any.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.SignedAttributes">
+            return a table of the signed attributes - indexed by
+            the OID of the attribute.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.UnsignedAttributes">
+            return a table of the unsigned attributes indexed by
+            the OID of the attribute.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformationStore.GetFirstSigner(Org.BouncyCastle.Cms.SignerID)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformationStore.GetSigners">
+            <returns>An ICollection of all signers in the collection</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformationStore.GetSigners(Org.BouncyCastle.Cms.SignerID)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformationStore.Count">
+            <summary>The number of signers in the collection.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.SimpleAttributeTableGenerator">
+            Basic generator that just returns a preconstructed attribute table
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.DHAgreement">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.DHAgreement.CalculateMessage">
+            calculate our initial message.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.DHAgreement.CalculateAgreement(Org.BouncyCastle.Crypto.Parameters.DHPublicKeyParameters,Org.BouncyCastle.Math.BigInteger)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.DHBasicAgreement">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IBasicAgreement">
+            The basic interface that basic Diffie-Hellman implementations
+            conforms to.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBasicAgreement.Init(Org.BouncyCastle.Crypto.ICipherParameters)">
+            initialise the agreement engine.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBasicAgreement.CalculateAgreement(Org.BouncyCastle.Crypto.ICipherParameters)">
+            given a public key from a given party calculate the next
+            message in the agreement sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.DHBasicAgreement.CalculateAgreement(Org.BouncyCastle.Crypto.ICipherParameters)">
+            given a short term public key from a given party calculate the next
+            message in the agreement sequence.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.ECDHBasicAgreement">
+             P1363 7.2.1 ECSVDP-DH
+            
+             ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive,
+             Diffie-Hellman version. It is based on the work of [DH76], [Mil86],
+             and [Kob87]. This primitive derives a shared secret value from one
+             party's private key and another party's public key, where both have
+             the same set of EC domain parameters. If two parties correctly
+             execute this primitive, they will produce the same output. This
+             primitive can be invoked by a scheme to derive a shared secret key;
+             specifically, it may be used with the schemes ECKAS-DH1 and
+             DL/ECKAS-DH2. It assumes that the input keys are valid (see also
+             Section 7.2.2).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.ECDHCBasicAgreement">
+             P1363 7.2.2 ECSVDP-DHC
+            
+             ECSVDP-DHC is Elliptic Curve Secret Value Derivation Primitive,
+             Diffie-Hellman version with cofactor multiplication. It is based on
+             the work of [DH76], [Mil86], [Kob87], [LMQ98] and [Kal98a]. This
+             primitive derives a shared secret value from one party's private key
+             and another party's public key, where both have the same set of EC
+             domain parameters. If two parties correctly execute this primitive,
+             they will produce the same output. This primitive can be invoked by a
+             scheme to derive a shared secret key; specifically, it may be used
+             with the schemes ECKAS-DH1 and DL/ECKAS-DH2. It does not assume the
+             validity of the input public key (see also Section 7.2.1).
+             <p>
+             Note: As stated P1363 compatibility mode with ECDH can be preset, and
+             in this case the implementation doesn't have a ECDH compatibility mode
+             (if you want that just use ECDHBasicAgreement and note they both implement
+             BasicAgreement!).</p>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IDerivationParameters">
+            Parameters for key/byte stream derivation classes
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.Kdf.DHKekGenerator">
+            RFC 2631 Diffie-hellman KEK derivation function.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IDerivationFunction">
+            base interface for general purpose byte derivation functions.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IDerivationFunction.Digest">
+            return the message digest used as the basis for the function
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.Kdf.ECDHKekGenerator">
+            X9.63 based key derivation function for ECDH CMS.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Client">
+            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"
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Client.Init(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Crypto.IDigest,Org.BouncyCastle.Security.SecureRandom)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Client.GenerateClientCredentials(System.Byte[],System.Byte[],System.Byte[])">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Client.CalculateSecret(Org.BouncyCastle.Math.BigInteger)">
+            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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Server">
+            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"
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Server.Init(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Crypto.IDigest,Org.BouncyCastle.Security.SecureRandom)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Server.GenerateServerCredentials">
+            Generates the server's credentials that are to be sent to the client.
+            @return The server's public value to the client
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Server.CalculateSecret(Org.BouncyCastle.Math.BigInteger)">
+            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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6VerifierGenerator">
+            Generates new SRP verifier for user
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6VerifierGenerator.Init(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Crypto.IDigest)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6VerifierGenerator.GenerateVerifier(System.Byte[],System.Byte[],System.Byte[])">
+            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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair">
+            a holding class for public/private parameter pairs.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+             basic constructor.
+            
+             @param publicParam a public key parameters object.
+             @param privateParam the corresponding private key parameters.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair.Public">
+             return the public key parameters.
+            
+             @return the public key parameters.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair.Private">
+             return the private key parameters.
+            
+             @return the private key parameters.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher">
+            The AEAD block ciphers already handle buffering internally, so this class
+            just takes care of implementing IBufferedCipher methods.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IBufferedCipher">
+            <remarks>Block cipher engines are expected to conform to this interface.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBufferedCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBufferedCipher.Reset">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IBufferedCipher.AlgorithmName">
+            <summary>The name of the algorithm this cipher implements.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.GetBlockSize">
+             return the blocksize for the underlying cipher.
+            
+             @return the blocksize for the underlying cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.GetUpdateOutputSize(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.GetOutputSize(System.Int32)">
+             return the size of the output buffer required for an update plus a
+             doFinal with an input of len bytes.
+            
+             @param len the length of the input.
+             @return the space required to accommodate a call to update and doFinal
+             with len bytes of input.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.DoFinal(System.Byte[],System.Int32)">
+             Process the last block in the buffer.
+            
+             @param out the array the block currently being held is copied into.
+             @param outOff the offset at which the copying starts.
+             @return the number of output bytes copied to out.
+             @exception DataLengthException if there is insufficient space in out for
+             the output, or the input is not block size aligned and should be.
+             @exception InvalidOperationException if the underlying cipher is not
+             initialised.
+             @exception InvalidCipherTextException if padding is expected and not found.
+             @exception DataLengthException if the input is not block size
+             aligned.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.Reset">
+            Reset the buffer and cipher. After resetting the object is in the same
+            state as it was after the last init (if there was one).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher">
+            a buffer wrapper for an asymmetric block cipher, allowing input
+            to be accumulated in a piecemeal fashion until final processing.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher)">
+             base constructor.
+            
+             @param cipher the cipher this buffering object wraps.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher.GetBufferPosition">
+             return the amount of data sitting in the buffer.
+            
+             @return the amount of data sitting in the buffer.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher.DoFinal">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher.Reset">
+            <summary>Reset the buffer</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.BufferedBlockCipher">
+            A wrapper class that allows block ciphers to be used to process data in
+            a piecemeal fashion. The BufferedBlockCipher outputs a block only when the
+            buffer is full and more data is being added, or on a doFinal.
+            <p>
+            Note: in the case where the underlying cipher is either a CFB cipher or an
+            OFB one the last block may not be a multiple of the block size.
+            </p>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.#ctor">
+            constructor for subclasses
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Create a buffered block cipher without padding.
+            
+             @param cipher the underlying block cipher this buffering object wraps.
+             false otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.GetBlockSize">
+             return the blocksize for the underlying cipher.
+            
+             @return the blocksize for the underlying cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.GetUpdateOutputSize(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.GetOutputSize(System.Int32)">
+             return the size of the output buffer required for an update plus a
+             doFinal with an input of len bytes.
+            
+             @param len the length of the input.
+             @return the space required to accommodate a call to update and doFinal
+             with len bytes of input.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.DoFinal(System.Byte[],System.Int32)">
+             Process the last block in the buffer.
+            
+             @param out the array the block currently being held is copied into.
+             @param outOff the offset at which the copying starts.
+             @return the number of output bytes copied to out.
+             @exception DataLengthException if there is insufficient space in out for
+             the output, or the input is not block size aligned and should be.
+             @exception InvalidOperationException if the underlying cipher is not
+             initialised.
+             @exception InvalidCipherTextException if padding is expected and not found.
+             @exception DataLengthException if the input is not block size
+             aligned.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.Reset">
+            Reset the buffer and cipher. After resetting the object is in the same
+            state as it was after the last init (if there was one).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.CipherKeyGenerator">
+            The base class for symmetric, or secret, cipher key generators.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.CipherKeyGenerator.Init(Org.BouncyCastle.Crypto.KeyGenerationParameters)">
+             initialise the key generator.
+            
+             @param param the parameters to be used for key generation
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.CipherKeyGenerator.GenerateKey">
+             Generate a secret key.
+            
+             @return a byte array containing the key value.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.DataLengthException">
+            this exception is thrown if a buffer that is meant to have output
+            copied into it turns out to be too short, or if we've been given
+            insufficient input. In general this exception will Get thrown rather
+            than an ArrayOutOfBounds exception.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.DataLengthException.#ctor">
+            base constructor.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.DataLengthException.#ctor(System.String)">
+             create a DataLengthException with the given message.
+            
+             @param message the message to be carried with the exception.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.GeneralDigest">
+            base implementation of MD4 family style digest as outlined in
+            "Handbook of Applied Cryptography", pages 344 - 347.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IDigest">
+            interface that a message digest conforms to.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDigest.GetDigestSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDigest.GetByteLength">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDigest.Update(System.Byte)">
+             update the message digest with a single byte.
+            
+             @param inByte the input byte to be entered.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDigest.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDigest.DoFinal(System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDigest.Reset">
+            reset the digest back to it's initial state.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IDigest.AlgorithmName">
+             return the algorithm name
+            
+             @return the algorithm name
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.Gost3411Digest">
+            implementation of GOST R 34.11-94
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Gost3411Digest.#ctor">
+            Standard constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Gost3411Digest.#ctor(System.Byte[])">
+            Constructor to allow use of a particular sbox with GOST28147
+            @see GOST28147Engine#getSBox(String)
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Gost3411Digest.#ctor(Org.BouncyCastle.Crypto.Digests.Gost3411Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Digests.Gost3411Digest.C2">
+            reset the chaining variables to the IV values.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.LongDigest">
+            Base class for SHA-384 and SHA-512.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.LongDigest.#ctor">
+            Constructor for variable length word
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.LongDigest.#ctor(Org.BouncyCastle.Crypto.Digests.LongDigest)">
+            Copy constructor.  We are using copy constructors in place
+            of the object.Clone() interface as this interface is not
+            supported by J2ME.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.LongDigest.AdjustByteCounts">
+            adjust the byte counts so that byteCount2 represents the
+            upper long (less 3 bits) word of the byte count.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.MD2Digest">
+            implementation of MD2
+            as outlined in RFC1319 by B.Kaliski from RSA Laboratories April 1992
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD2Digest.DoFinal(System.Byte[],System.Int32)">
+             Close the digest, producing the final digest value. The doFinal
+             call leaves the digest reset.
+            
+             @param out the array the digest is to be copied into.
+             @param outOff the offset into the out array the digest is to start at.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD2Digest.Reset">
+            reset the digest back to it's initial state.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD2Digest.Update(System.Byte)">
+             update the message digest with a single byte.
+            
+             @param in the input byte to be entered.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD2Digest.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+             update the message digest with a block of bytes.
+            
+             @param in the byte array containing the data.
+             @param inOff the offset into the byte array where the data starts.
+             @param len the length of the data.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Digests.MD2Digest.AlgorithmName">
+             return the algorithm name
+            
+             @return the algorithm name
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.MD4Digest">
+            implementation of MD4 as RFC 1320 by R. Rivest, MIT Laboratory for
+            Computer Science and RSA Data Security, Inc.
+            <p>
+            <b>NOTE</b>: This algorithm is only included for backwards compatibility
+            with legacy applications, it's not secure, don't use it for anything new!</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD4Digest.#ctor">
+            Standard constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD4Digest.#ctor(Org.BouncyCastle.Crypto.Digests.MD4Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD4Digest.Reset">
+            reset the chaining variables to the IV values.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.MD5Digest">
+            implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD5Digest.#ctor(Org.BouncyCastle.Crypto.Digests.MD5Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD5Digest.Reset">
+            reset the chaining variables to the IV values.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.RipeMD128Digest">
+            implementation of RipeMD128
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD128Digest.#ctor">
+            Standard constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD128Digest.#ctor(Org.BouncyCastle.Crypto.Digests.RipeMD128Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD128Digest.Reset">
+            reset the chaining variables to the IV values.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.RipeMD160Digest">
+            implementation of RipeMD see,
+            http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD160Digest.#ctor">
+            Standard constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD160Digest.#ctor(Org.BouncyCastle.Crypto.Digests.RipeMD160Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD160Digest.Reset">
+            reset the chaining variables to the IV values.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.RipeMD256Digest">
+            <remarks>
+            <p>Implementation of RipeMD256.</p>
+            <p><b>Note:</b> this algorithm offers the same level of security as RipeMD128.</p>
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD256Digest.#ctor">
+            <summary> Standard constructor</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD256Digest.#ctor(Org.BouncyCastle.Crypto.Digests.RipeMD256Digest)">
+            <summary> Copy constructor.  This will copy the state of the provided
+            message digest.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD256Digest.Reset">
+            <summary> reset the chaining variables to the IV values.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.RipeMD320Digest">
+            <remarks>
+            <p>Implementation of RipeMD 320.</p>
+            <p><b>Note:</b> this algorithm offers the same level of security as RipeMD160.</p>
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD320Digest.#ctor">
+            <summary> Standard constructor</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD320Digest.#ctor(Org.BouncyCastle.Crypto.Digests.RipeMD320Digest)">
+            <summary> Copy constructor.  This will copy the state of the provided
+            message digest.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD320Digest.Reset">
+            <summary> reset the chaining variables to the IV values.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.Sha1Digest">
+             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!
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha1Digest.#ctor(Org.BouncyCastle.Crypto.Digests.Sha1Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha1Digest.Reset">
+            reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.Sha224Digest">
+            SHA-224 as described in RFC 3874
+            <pre>
+                    block  word  digest
+            SHA-1   512    32    160
+            SHA-224 512    32    224
+            SHA-256 512    32    256
+            SHA-384 1024   64    384
+            SHA-512 1024   64    512
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha224Digest.#ctor">
+            Standard constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha224Digest.#ctor(Org.BouncyCastle.Crypto.Digests.Sha224Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha224Digest.Reset">
+            reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.Sha256Digest">
+             Draft FIPS 180-2 implementation of SHA-256. <b>Note:</b> As this is
+             based on a draft this implementation is subject to change.
+            
+             <pre>
+                     block  word  digest
+             SHA-1   512    32    160
+             SHA-256 512    32    256
+             SHA-384 1024   64    384
+             SHA-512 1024   64    512
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha256Digest.#ctor(Org.BouncyCastle.Crypto.Digests.Sha256Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha256Digest.Reset">
+            reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.Sha384Digest">
+             Draft FIPS 180-2 implementation of SHA-384. <b>Note:</b> As this is
+             based on a draft this implementation is subject to change.
+            
+             <pre>
+                     block  word  digest
+             SHA-1   512    32    160
+             SHA-256 512    32    256
+             SHA-384 1024   64    384
+             SHA-512 1024   64    512
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha384Digest.#ctor(Org.BouncyCastle.Crypto.Digests.Sha384Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha384Digest.Reset">
+            reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.Sha512Digest">
+             Draft FIPS 180-2 implementation of SHA-512. <b>Note:</b> As this is
+             based on a draft this implementation is subject to change.
+            
+             <pre>
+                     block  word  digest
+             SHA-1   512    32    160
+             SHA-256 512    32    256
+             SHA-384 1024   64    384
+             SHA-512 1024   64    512
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha512Digest.#ctor(Org.BouncyCastle.Crypto.Digests.Sha512Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha512Digest.Reset">
+            reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.ShortenedDigest">
+            Wrapper class that reduces the output length of a particular digest to
+            only the first n bytes of the digest function.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.ShortenedDigest.#ctor(Org.BouncyCastle.Crypto.IDigest,System.Int32)">
+             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().
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.TigerDigest">
+            implementation of Tiger based on:
+            <a href="http://www.cs.technion.ac.il/~biham/Reports/Tiger">
+             http://www.cs.technion.ac.il/~biham/Reports/Tiger</a>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.TigerDigest.#ctor">
+            Standard constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.TigerDigest.#ctor(Org.BouncyCastle.Crypto.Digests.TigerDigest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.TigerDigest.Reset">
+            reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.WhirlpoolDigest">
+             Implementation of WhirlpoolDigest, based on Java source published by Barreto
+             and Rijmen.
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.WhirlpoolDigest.#ctor(Org.BouncyCastle.Crypto.Digests.WhirlpoolDigest)">
+            Copy constructor. This will copy the state of the provided message
+            digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.WhirlpoolDigest.Reset">
+            Reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Encodings.ISO9796d1Encoding">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IAsymmetricBlockCipher">
+            <remarks>Base interface for a public/private key block cipher.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IAsymmetricBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IAsymmetricBlockCipher.GetInputBlockSize">
+            <returns>The maximum size, in bytes, an input block may be.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IAsymmetricBlockCipher.GetOutputBlockSize">
+            <returns>The maximum size, in bytes, an output block will be.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IAsymmetricBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Int32)">
+            <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="T:Org.BouncyCastle.Crypto.InvalidCipherTextException">Input decrypts improperly.</exception>
+            <exception cref="T:Org.BouncyCastle.Crypto.DataLengthException">Input is too large for the cipher.</exception>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IAsymmetricBlockCipher.AlgorithmName">
+            <summary>The name of the algorithm this cipher implements.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.ISO9796d1Encoding.GetInputBlockSize">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.ISO9796d1Encoding.GetOutputBlockSize">
+            return the maximum possible size for the output.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.ISO9796d1Encoding.SetPadBits(System.Int32)">
+            set the number of bits in the next message to be treated as
+            pad bits.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.ISO9796d1Encoding.GetPadBits">
+            retrieve the number of pad bits in the last decoded message.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.ISO9796d1Encoding.DecodeBlock(System.Byte[],System.Int32,System.Int32)">
+            @exception InvalidCipherTextException if the decrypted block is not a valid ISO 9796 bit string
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Encodings.OaepEncoding">
+            Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.OaepEncoding.decodeBlock(System.Byte[],System.Int32,System.Int32)">
+            @exception InvalidCipherTextException if the decrypted block turns out to
+            be badly formatted.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.OaepEncoding.ItoOSP(System.Int32,System.Byte[])">
+            int to octet string.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.OaepEncoding.maskGeneratorFunction1(System.Byte[],System.Int32,System.Int32,System.Int32)">
+            mask generator function, as described in PKCS1v2.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.StrictLengthEnabledProperty">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher)">
+            Basic constructor.
+            @param cipher
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.DecodeBlock(System.Byte[],System.Int32,System.Int32)">
+            @exception InvalidCipherTextException if the decrypted block is not in Pkcs1 format.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.StrictLengthEnabled">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.AesEngine">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IBlockCipher">
+            <remarks>Base interface for a symmetric key block cipher.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBlockCipher.GetBlockSize">
+            <returns>The block size for this cipher, in bytes.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+            <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="T:Org.BouncyCastle.Crypto.DataLengthException">If input block is wrong size, or outBuf too small.</exception>
+            <returns>The number of bytes processed and produced.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBlockCipher.Reset">
+            <summary>
+            Reset the cipher to the same state as it was after the last init (if there was one).
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IBlockCipher.AlgorithmName">
+            <summary>The name of the algorithm this cipher implements.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IBlockCipher.IsPartialBlockOkay">
+            <summary>Indicates whether this cipher can handle partial blocks.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesEngine.GenerateWorkingKey(System.Byte[],System.Boolean)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesEngine.#ctor">
+            default constructor - 128 bit block size.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.AesFastEngine">
+             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 fast version with 8Kbytes of static tables for round precomputation
+             </p>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesFastEngine.GenerateWorkingKey(System.Byte[],System.Boolean)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesFastEngine.#ctor">
+            default constructor - 128 bit block size.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesFastEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.AesLightEngine">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesLightEngine.GenerateWorkingKey(System.Byte[],System.Boolean)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesLightEngine.#ctor">
+            default constructor - 128 bit block size.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesLightEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.AesWrapEngine">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.Rfc3394WrapEngine">
+            <remarks>
+            An implementation of the AES Key Wrapper from the NIST Key Wrap
+            Specification as described in RFC 3394.
+            <p/>
+            For further details see: <a href="http://www.ietf.org/rfc/rfc3394.txt">http://www.ietf.org/rfc/rfc3394.txt</a>
+            and  <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
+            </remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IWrapper.AlgorithmName">
+            <summary>The name of the algorithm this cipher implements.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.BlowfishEngine">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.BlowfishEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.BlowfishEngine.ProcessTable(System.UInt32,System.UInt32,System.UInt32[])">
+            apply the encryption cycle to each value pair in the table.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.BlowfishEngine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.BlowfishEngine.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.CamelliaEngine">
+            Camellia - based on RFC 3713.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.CamelliaLightEngine">
+            Camellia - based on RFC 3713, smaller implementation, about half the size of CamelliaEngine.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.CamelliaWrapEngine">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.Cast5Engine">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.F1(System.UInt32,System.UInt32,System.Int32)">
+             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
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.F2(System.UInt32,System.UInt32,System.Int32)">
+             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
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.F3(System.UInt32,System.UInt32,System.Int32)">
+             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
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.CAST_Encipher(System.UInt32,System.UInt32,System.UInt32[])">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.Cast6Engine">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast6Engine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast6Engine.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast6Engine.CAST_Encipher(System.UInt32,System.UInt32,System.UInt32,System.UInt32,System.UInt32[])">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast6Engine.CAST_Decipher(System.UInt32,System.UInt32,System.UInt32,System.UInt32,System.UInt32[])">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.DesEdeEngine">
+            <remarks>A class that provides a basic DESede (or Triple DES) engine.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.DesEngine">
+            <remarks>A class that provides a basic DES engine.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEngine.bytebit">
+            what follows is mainly taken from "Applied Cryptography", by
+            Bruce Schneier, however it also bears great resemblance to Richard
+            Outerbridge's D3DES...
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEngine.GenerateWorkingKey(System.Boolean,System.Byte[])">
+             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!).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEngine.DesFunc(System.Int32[],System.Byte[],System.Int32,System.Byte[],System.Int32)">
+            the DES engine.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEdeEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine">
+                * 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>
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.engine">
+            Field engine 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.param">
+            Field param 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.paramPlusIV">
+            Field paramPlusIV 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.iv">
+            Field iv 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.forWrapping">
+            Field forWrapping 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.IV2">
+            Field IV2           
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Method init
+            
+             @param forWrapping
+             @param param
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.Wrap(System.Byte[],System.Int32,System.Int32)">
+             Method wrap
+            
+             @param in
+             @param inOff
+             @param inLen
+             @return
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.Unwrap(System.Byte[],System.Int32,System.Int32)">
+             Method unwrap
+            
+             @param in
+             @param inOff
+             @param inLen
+             @return
+             @throws InvalidCipherTextException
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.CalculateCmsKeyChecksum(System.Byte[])">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.CheckCmsKeyChecksum(System.Byte[],System.Byte[])">
+            @param key
+            @param checksum
+            @return
+            @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.AlgorithmName">
+             Method GetAlgorithmName
+            
+             @return
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.ElGamalEngine">
+            this does your basic ElGamal algorithm.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.ElGamalEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             initialise the ElGamal engine.
+            
+             @param forEncryption true if we are encrypting, false otherwise.
+             @param param the necessary ElGamal key parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.ElGamalEngine.GetInputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.ElGamalEngine.GetOutputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.ElGamalEngine.ProcessBlock(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.Gost28147Engine">
+            implementation of GOST 28147-89
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Gost28147Engine.#ctor">
+            standard constructor.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Gost28147Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             initialise an Gost28147 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Gost28147Engine.GetSBox(System.String)">
+            Return the S-Box associated with SBoxName
+            @param sBoxName name of the S-Box
+            @return byte array representing the S-Box
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.HC128Engine">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IStreamCipher">
+            <summary>The interface stream ciphers conform to.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IStreamCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            <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="T:System.ArgumentException">
+            If the parameters argument is inappropriate.
+            </exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IStreamCipher.ReturnByte(System.Byte)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IStreamCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+            <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="T:Org.BouncyCastle.Crypto.DataLengthException">If the output buffer is too small.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IStreamCipher.Reset">
+            <summary>
+            Reset the cipher to the same state as it was after the last init (if there was one).
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IStreamCipher.AlgorithmName">
+            <summary>The name of the algorithm this cipher implements.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.HC128Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.HC256Engine">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.HC256Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.IesEngine">
+            support class for constructing intergrated encryption ciphers
+            for doing basic message exchanges on top of key agreement ciphers
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.IesEngine.#ctor(Org.BouncyCastle.Crypto.IBasicAgreement,Org.BouncyCastle.Crypto.IDerivationFunction,Org.BouncyCastle.Crypto.IMac)">
+             set up for use with stream mode, where the key derivation function
+             is used to provide a stream of bytes to xor with the message.
+            
+             @param agree the key agreement used as the basis for the encryption
+             @param kdf the key derivation function used for byte generation
+             @param mac the message authentication code generator for the message
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.IesEngine.#ctor(Org.BouncyCastle.Crypto.IBasicAgreement,Org.BouncyCastle.Crypto.IDerivationFunction,Org.BouncyCastle.Crypto.IMac,Org.BouncyCastle.Crypto.BufferedBlockCipher)">
+             set up for use in conjunction with a block cipher to handle the
+             message.
+            
+             @param agree the key agreement used as the basis for the encryption
+             @param kdf the key derivation function used for byte generation
+             @param mac the message authentication code generator for the message
+             @param cipher the cipher to used for encrypting the message
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.IesEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters,Org.BouncyCastle.Crypto.ICipherParameters,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the encryptor.
+            
+             @param forEncryption whether or not this is encryption/decryption.
+             @param privParam our private key parameters
+             @param pubParam the recipient's/sender's public key parameters
+             @param param encoding and derivation parameters.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.IsaacEngine">
+            Implementation of Bob Jenkin's ISAAC (Indirection Shift Accumulate Add and Count).
+            see: http://www.burtleburtle.net/bob/rand/isaacafa.html
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.IsaacEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine">
+            NaccacheStern Engine. For details on this cipher, please see
+            http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initializes this algorithm. Must be called before all other Functions.
+            
+             @see org.bouncycastle.crypto.AsymmetricBlockCipher#init(bool,
+                  org.bouncycastle.crypto.CipherParameters)
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.GetInputBlockSize">
+             Returns the input block size of this algorithm.
+            
+             @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetInputBlockSize()
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.GetOutputBlockSize">
+             Returns the output block size of this algorithm.
+            
+             @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetOutputBlockSize()
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.ProcessBlock(System.Byte[],System.Int32,System.Int32)">
+             Process a single Block using the Naccache-Stern algorithm.
+            
+             @see org.bouncycastle.crypto.AsymmetricBlockCipher#ProcessBlock(byte[],
+                  int, int)
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.Encrypt(Org.BouncyCastle.Math.BigInteger)">
+             Encrypts a BigInteger aka Plaintext with the public key.
+            
+             @param plain
+                        The BigInteger to encrypt
+             @return The byte[] representation of the encrypted BigInteger (i.e.
+                     crypted.toByteArray())
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.AddCryptedBlocks(System.Byte[],System.Byte[])">
+             Adds the contents of two encrypted blocks mod sigma
+            
+             @param block1
+                        the first encrypted block
+             @param block2
+                        the second encrypted block
+             @return encrypt((block1 + block2) mod sigma)
+             @throws InvalidCipherTextException
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.ProcessData(System.Byte[])">
+             Convenience Method for data exchange with the cipher.
+            
+             Determines blocksize and splits data to blocksize.
+            
+             @param data the data to be processed
+             @return the data after it went through the NaccacheSternEngine.
+             @throws InvalidCipherTextException
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.chineseRemainder(System.Collections.IList,System.Collections.IList)">
+             Computes the integer x that is expressed through the given primes and the
+             congruences with the chinese remainder theorem (CRT).
+            
+             @param congruences
+                        the congruences c_i
+             @param primes
+                        the primes p_i
+             @return an integer x for that x % p_i == c_i
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.NoekeonEngine">
+            A Noekeon engine, using direct-key mode.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NoekeonEngine.#ctor">
+            Create an instance of the Noekeon encryption algorithm
+            and set some defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NoekeonEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NoekeonEngine.setKey(System.Byte[])">
+             Re-key the cipher.
+            
+             @param  key  the key to be used
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.NullEngine">
+            The no-op engine that just copies bytes through, irrespective of whether encrypting and decrypting.
+            Provided for the sake of completeness.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RC2Engine">
+            an implementation of RC2 as described in RFC 2268
+                 "A Description of the RC2(r) Encryption Algorithm" R. Rivest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2Engine.RotateWordLeft(System.Int32,System.Int32)">
+            return the result rotating the 16 bit number in x left by y
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine">
+            Wrap keys according to RFC 3217 - RC2 mechanism
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.engine">
+            Field engine 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.parameters">
+            Field param 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.paramPlusIV">
+            Field paramPlusIV 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.iv">
+            Field iv 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.forWrapping">
+            Field forWrapping 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.IV2">
+            Field IV2           
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Method init
+            
+             @param forWrapping
+             @param param
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.Wrap(System.Byte[],System.Int32,System.Int32)">
+             Method wrap
+            
+             @param in
+             @param inOff
+             @param inLen
+             @return
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.Unwrap(System.Byte[],System.Int32,System.Int32)">
+             Method unwrap
+            
+             @param in
+             @param inOff
+             @param inLen
+             @return
+             @throws InvalidCipherTextException
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.CalculateCmsKeyChecksum(System.Byte[])">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.CheckCmsKeyChecksum(System.Byte[],System.Byte[])">
+            @param key
+            @param checksum
+            @return
+            @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.AlgorithmName">
+             Method GetAlgorithmName
+            
+             @return
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC4Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RC532Engine">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC532Engine.#ctor">
+            Create an instance of the RC5 encryption algorithm
+            and set some defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC532Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC532Engine.SetKey(System.Byte[])">
+             Re-key the cipher.
+            
+             @param  key  the key to be used
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC532Engine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC532Engine.RotateLeft(System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC532Engine.RotateRight(System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RC564Engine">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC564Engine.#ctor">
+            Create an instance of the RC5 encryption algorithm
+            and set some defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC564Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC564Engine.SetKey(System.Byte[])">
+             Re-key the cipher.
+            
+             @param  key  the key to be used
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC564Engine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC564Engine.RotateLeft(System.Int64,System.Int64)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC564Engine.RotateRight(System.Int64,System.Int64)">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RC6Engine">
+            An RC6 engine.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC6Engine.#ctor">
+            Create an instance of the RC6 encryption algorithm
+            and set some defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC6Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC6Engine.SetKey(System.Byte[])">
+             Re-key the cipher.
+            
+             @param inKey the key to be used
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC6Engine.RotateLeft(System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC6Engine.RotateRight(System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.Rfc3211WrapEngine">
+            an implementation of the RFC 3211 Key Wrap
+            Specification.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RijndaelEngine">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.Mul0x2(System.Int32)">
+            multiply two elements of GF(2^m)
+            needed for MixColumn and InvMixColumn
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.KeyAddition(System.Int64[])">
+            xor corresponding text input and round key input bytes
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.ShiftRow(System.Byte[])">
+            Row 0 remains unchanged
+            The other three rows are shifted a variable amount
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.Substitution(System.Byte[])">
+            Replace every byte of the input by the byte at that place
+            in the nonlinear S-box
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.MixColumn">
+            Mix the bytes of every column in a linear way
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.InvMixColumn">
+            Mix the bytes of every column in a linear way
+            This is the opposite operation of Mixcolumn
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.GenerateWorkingKey(System.Byte[])">
+            Calculate the necessary round keys
+            The number of calculations depends on keyBits and blockBits
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.#ctor">
+            default constructor - 128 bit block size.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.#ctor(System.Int32)">
+             basic constructor - set the cipher up for a given blocksize
+            
+             @param blocksize the blocksize in bits, must be 128, 192, or 256.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine">
+            this does your basic RSA algorithm with blinding
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             initialise the RSA engine.
+            
+             @param forEncryption true if we are encrypting, false otherwise.
+             @param param the necessary RSA key parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine.GetInputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine.GetOutputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine.ProcessBlock(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RsaBlindingEngine">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindingEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the blinding engine.
+            
+             @param forEncryption true if we are encrypting (blinding), false otherwise.
+             @param param         the necessary RSA key parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindingEngine.GetInputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindingEngine.GetOutputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindingEngine.ProcessBlock(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RsaCoreEngine">
+            this does your basic RSA algorithm.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaCoreEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             initialise the RSA engine.
+            
+             @param forEncryption true if we are encrypting, false otherwise.
+             @param param the necessary RSA key parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaCoreEngine.GetInputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaCoreEngine.GetOutputBlockSize">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RsaEngine">
+            this does your basic RSA algorithm.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             initialise the RSA engine.
+            
+             @param forEncryption true if we are encrypting, false otherwise.
+             @param param the necessary RSA key parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaEngine.GetInputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaEngine.GetOutputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaEngine.ProcessBlock(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.Salsa20Engine">
+            Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.Salsa20Engine.StateSize">
+            Constants 
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Salsa20Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.SeedEngine">
+            Implementation of the SEED algorithm as described in RFC 4009
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.SeedWrapEngine">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.SerpentEngine">
+                * 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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.MakeWorkingKey(System.Byte[])">
+             Expand a user-supplied key material into a session key.
+            
+             @param key  The user-key bytes (multiples of 4) to use.
+             @exception ArgumentException
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb0(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib0(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb1(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib1(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb2(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib2(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb3(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib3(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb4(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib4(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb5(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib5(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb6(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib6(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb7(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib7(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.LT">
+            Apply the linear transformation to the register set.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.InverseLT">
+            Apply the inverse of the linear transformation to the register set.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.SkipjackEngine">
+            a class that provides a basic SKIPJACK engine.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SkipjackEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SkipjackEngine.G(System.Int32,System.Int32)">
+            The G permutation
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SkipjackEngine.H(System.Int32,System.Int32)">
+            the inverse of the G permutation.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.TeaEngine">
+            An TEA engine.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TeaEngine.#ctor">
+            Create an instance of the TEA encryption algorithm
+            and set some defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TeaEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TeaEngine.setKey(System.Byte[])">
+             Re-key the cipher.
+            
+             @param  key  the key to be used
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.TwofishEngine">
+             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.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.TwofishEngine.P_00">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.TwofishEngine.gSubKeys">
+            gSubKeys[] and gSBox[] are eventually used in the
+            encryption and decryption methods.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TwofishEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TwofishEngine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TwofishEngine.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TwofishEngine.RS_MDS_Encode(System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TwofishEngine.RS_rem(System.Int32)">
+                    * 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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.VmpcEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.XteaEngine">
+            An XTEA engine.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.XteaEngine.#ctor">
+            Create an instance of the TEA encryption algorithm
+            and set some defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.XteaEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.XteaEngine.setKey(System.Byte[])">
+             Re-key the cipher.
+            
+             @param  key  the key to be used
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.BaseKdfBytesGenerator">
+            Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+            <br/>
+            This implementation is based on ISO 18033/P1363a.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.BaseKdfBytesGenerator.#ctor(System.Int32,Org.BouncyCastle.Crypto.IDigest)">
+             Construct a KDF Parameters generator.
+            
+             @param counterStart value of counter.
+             @param digest the digest to be used as the source of derived keys.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.BaseKdfBytesGenerator.GenerateBytes(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Generators.BaseKdfBytesGenerator.Digest">
+            return the underlying digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.DesKeyGenerator.engineInit(Org.BouncyCastle.Crypto.KeyGenerationParameters)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.DesEdeKeyGenerator.engineInit(Org.BouncyCastle.Crypto.KeyGenerationParameters)">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.DHBasicKeyPairGenerator">
+             a basic Diffie-Hellman key pair generator.
+            
+             This generates keys consistent for use with the basic algorithm for
+             Diffie-Hellman.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IAsymmetricCipherKeyPairGenerator">
+            interface that a public/private key pair generator should conform to.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IAsymmetricCipherKeyPairGenerator.Init(Org.BouncyCastle.Crypto.KeyGenerationParameters)">
+             intialise the key pair generator.
+            
+             @param the parameters the key pair is to be initialised with.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IAsymmetricCipherKeyPairGenerator.GenerateKeyPair">
+             return an AsymmetricCipherKeyPair containing the Generated keys.
+            
+             @return an AsymmetricCipherKeyPair containing the Generated keys.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.DHKeyPairGenerator">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.DHParametersGenerator.GenerateParameters">
+            which Generates the p and g values from the given parameters,
+            returning the DHParameters object.
+            <p>
+            Note: can take a while...</p>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.DsaKeyPairGenerator">
+                 * 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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.DsaParametersGenerator">
+            Generate suitable parameters for DSA, in line with FIPS 186-2.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.DsaParametersGenerator.Init(System.Int32,System.Int32,Org.BouncyCastle.Security.SecureRandom)">
+             initialise the key generator.
+            
+             @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments)
+             @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
+             @param random random byte source.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.DsaParametersGenerator.GenerateParameters">
+            which Generates the p and g values from the given parameters,
+            returning the DsaParameters object.
+            <p>
+            Note: can take a while...</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.DsaParametersGenerator.GenerateParameters_FIPS186_3">
+            generate suitable parameters for DSA, in line with
+            <i>FIPS 186-3 A.1 Generation of the FFC Primes p and q</i>.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator.GenerateKeyPair">
+            Given the domain parameters this routine Generates an EC key
+            pair in accordance with X9.62 section 5.2.1 pages 26, 27.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.ElGamalKeyPairGenerator">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.ElGamalParametersGenerator.GenerateParameters">
+                     * which Generates the p and g values from the given parameters,
+                     * returning the ElGamalParameters object.
+                     * <p>
+                     * Note: can take a while...
+            		 * </p>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Gost3410KeyPairGenerator">
+            a GOST3410 key pair generator.
+            This generates GOST3410 keys in line with the method described
+            in GOST R 34.10-94.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Gost3410ParametersGenerator">
+            generate suitable parameters for GOST3410.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Gost3410ParametersGenerator.Init(System.Int32,System.Int32,Org.BouncyCastle.Security.SecureRandom)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Gost3410ParametersGenerator.procedure_C(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            Procedure C
+            procedure generates the a value from the given p,q,
+            returning the a value.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Gost3410ParametersGenerator.GenerateParameters">
+            which generates the p , q and a values from the given parameters,
+            returning the Gost3410Parameters object.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Kdf1BytesGenerator">
+            KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+            <br/>
+            This implementation is based on IEEE P1363/ISO 18033.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Kdf1BytesGenerator.#ctor(Org.BouncyCastle.Crypto.IDigest)">
+             Construct a KDF1 byte generator.
+            
+             @param digest the digest to be used as the source of derived keys.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Kdf2BytesGenerator">
+            KDF2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+            <br/>
+            This implementation is based on IEEE P1363/ISO 18033.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Kdf2BytesGenerator.#ctor(Org.BouncyCastle.Crypto.IDigest)">
+             Construct a KDF2 bytes generator. Generates key material
+             according to IEEE P1363 or ISO 18033 depending on the initialisation.
+            
+             @param digest the digest to be used as the source of derived keys.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Mgf1BytesGenerator">
+            Generator for MGF1 as defined in Pkcs 1v2
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Mgf1BytesGenerator.#ctor(Org.BouncyCastle.Crypto.IDigest)">
+            @param digest the digest to be used as the source of Generated bytes
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Mgf1BytesGenerator.ItoOSP(System.Int32,System.Byte[])">
+            int to octet string.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Mgf1BytesGenerator.GenerateBytes(System.Byte[],System.Int32,System.Int32)">
+             fill len bytes of the output buffer with bytes Generated from
+             the derivation function.
+            
+             @throws DataLengthException if the out buffer is too small.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Generators.Mgf1BytesGenerator.Digest">
+            return the underlying digest.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.NaccacheSternKeyPairGenerator">
+             Key generation parameters for NaccacheStern cipher. For details on this cipher, please see
+            
+             http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.NaccacheSternKeyPairGenerator.permuteList(System.Collections.IList,Org.BouncyCastle.Security.SecureRandom)">
+             Generates a permuted ArrayList from the original one. The original List
+             is not modified
+            
+             @param arr
+                        the ArrayList to be permuted
+             @param rand
+                        the source of Randomness for permutation
+             @return a new ArrayList with the permuted elements.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.NaccacheSternKeyPairGenerator.findFirstPrimes(System.Int32)">
+             Finds the first 'count' primes starting with 3
+            
+             @param count
+                        the number of primes to find
+             @return a vector containing the found primes as Integer
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.PbeParametersGenerator">
+            super class for all Password Based Encyrption (Pbe) parameter generator classes.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.#ctor">
+            base constructor.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.Init(System.Byte[],System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.GetPassword">
+             return the password byte array.
+            
+             @return the password byte array.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.GetSalt">
+             return the salt byte array.
+            
+             @return the salt byte array.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.GenerateDerivedParameters(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.GenerateDerivedParameters(System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.GenerateDerivedMacParameters(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.Pkcs5PasswordToBytes(System.Char[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.Pkcs5PasswordToUtf8Bytes(System.Char[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.Pkcs12PasswordToBytes(System.Char[])">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.PbeParametersGenerator.IterationCount">
+             return the iteration count.
+            
+             @return the iteration count.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator.#ctor">
+            Construct a OpenSSL Parameters generator. 
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator.Init(System.Byte[],System.Byte[])">
+            Initialise - note the iteration count for this algorithm is fixed at 1.
+            
+            @param password password to use.
+            @param salt salt to use.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator.GenerateDerivedKey(System.Int32)">
+            the derived key function, the ith hash of the password and the salt.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator.GenerateDerivedParameters(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator.GenerateDerivedParameters(System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator.GenerateDerivedMacParameters(System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator.#ctor(Org.BouncyCastle.Crypto.IDigest)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator.Adjust(System.Byte[],System.Int32,System.Byte[])">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator.GenerateDerivedKey(System.Int32,System.Int32)">
+            generation of a derived key ala Pkcs12 V1.0.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator.GenerateDerivedParameters(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator.GenerateDerivedParameters(System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator.GenerateDerivedMacParameters(System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Pkcs5S1ParametersGenerator">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S1ParametersGenerator.#ctor(Org.BouncyCastle.Crypto.IDigest)">
+             Construct a Pkcs 5 Scheme 1 Parameters generator.
+            
+             @param digest the digest to be used as the source of derived keys.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S1ParametersGenerator.GenerateDerivedKey">
+            the derived key function, the ith hash of the mPassword and the mSalt.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S1ParametersGenerator.GenerateDerivedParameters(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S1ParametersGenerator.GenerateDerivedParameters(System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S1ParametersGenerator.GenerateDerivedMacParameters(System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator.#ctor">
+            construct a Pkcs5 Scheme 2 Parameters generator.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator.GenerateDerivedParameters(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator.GenerateDerivedParameters(System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator.GenerateDerivedMacParameters(System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.RsaBlindingFactorGenerator">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.RsaBlindingFactorGenerator.Init(Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the factor generator
+            
+             @param param the necessary RSA key parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.RsaBlindingFactorGenerator.GenerateBlindingFactor">
+             Generate a suitable blind factor for the public key the generator was initialised with.
+            
+             @return a random blind factor
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.RsaKeyPairGenerator">
+            an RSA key pair generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IDsa">
+            interface for classes implementing the Digital Signature Algorithm
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDsa.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDsa.GenerateSignature(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDsa.VerifySignature(System.Byte[],Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IMac">
+            The base interface for implementations of message authentication codes (MACs).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IMac.Init(Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the MAC.
+            
+             @param param the key and other data required by the MAC.
+             @exception ArgumentException if the parameters argument is
+             inappropriate.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IMac.GetMacSize">
+             Return the block size for this MAC (in bytes).
+            
+             @return the block size for this MAC in bytes.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IMac.Update(System.Byte)">
+             add a single byte to the mac for processing.
+            
+             @param in the byte to be processed.
+             @exception InvalidOperationException if the MAC is not initialised.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IMac.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            @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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IMac.DoFinal(System.Byte[],System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IMac.Reset">
+            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).
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IMac.AlgorithmName">
+             Return the name of the algorithm the MAC implements.
+            
+             @return the name of the algorithm the MAC implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.InvalidCipherTextException">
+            this exception is thrown whenever we find something we don't expect in a
+            message.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.InvalidCipherTextException.#ctor">
+            base constructor.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.InvalidCipherTextException.#ctor(System.String)">
+             create a InvalidCipherTextException with the given message.
+            
+             @param message the message to be carried with the exception.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISigner.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the signer for signing or verification.
+            
+             @param forSigning true if for signing, false otherwise
+             @param param necessary parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISigner.Update(System.Byte)">
+            update the internal digest with the byte b
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            update the internal digest with the byte array in
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISigner.GenerateSignature">
+            Generate a signature for the message we've been loaded with using
+            the key we were initialised with.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISigner.VerifySignature(System.Byte[])">
+            return true if the internal state represents the signature described
+            in the passed in array.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISigner.Reset">
+            reset the internal state
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.ISigner.AlgorithmName">
+             Return the name of the algorithm the signer implements.
+            
+             @return the name of the algorithm the signer implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.ISignerWithRecovery">
+            Signer with message recovery.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.HasFullMessage">
+             Returns true if the signer has recovered the full message as
+             part of signature verification.
+            
+             @return true if full message recovered.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.GetRecoveredMessage">
+             Returns a reference to what message was recovered (if any).
+            
+             @return full/partial message, null if nothing.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.UpdateWithRecoveredMessage(System.Byte[])">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.KeyGenerationParameters">
+            The base class for parameters to key generators.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.KeyGenerationParameters.#ctor(Org.BouncyCastle.Security.SecureRandom,System.Int32)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.KeyGenerationParameters.Random">
+             return the random source associated with this
+             generator.
+            
+             @return the generators random source.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.KeyGenerationParameters.Strength">
+             return the bit strength for keys produced by this generator,
+            
+             @return the strength of the keys this generator produces (in bits).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Macs.CbcBlockCipherMac">
+            standard CBC Block Cipher MAC - if no padding is specified the default of
+            pad of zeroes is used.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CbcBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CbcBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CbcBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CbcBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CbcBlockCipherMac.Reset">
+            Reset the mac generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher">
+            implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32)">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher.GetBlockSize">
+             return the block size we are operating at.
+            
+             @return the block size we are operating at (in bytes).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher.Reset">
+            reset the chaining vector back to the IV and reset the underlying
+            cipher.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher.AlgorithmName">
+             return the algorithm name and mode.
+            
+             @return the name of the underlying algorithm followed by "/CFB"
+             and the block size in bits.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CfbBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CfbBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CfbBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32,System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CfbBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32,System.Int32,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CfbBlockCipherMac.Reset">
+            Reset the mac generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Macs.CMac">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CMac.Reset">
+            Reset the mac generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Macs.Gost28147Mac">
+            implementation of GOST 28147-89 MAC
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Macs.HMac">
+             HMAC implementation based on RFC2104
+            
+             H(K XOR opad, H(K XOR ipad, text))
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.HMac.Reset">
+            Reset the mac generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Macs.ISO9797Alg3Mac">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.ISO9797Alg3Mac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.ISO9797Alg3Mac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.ISO9797Alg3Mac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.ISO9797Alg3Mac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.ISO9797Alg3Mac.Reset">
+            Reset the mac generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.MaxBytesExceededException">
+            <summary>
+            This exception is thrown whenever a cipher requires a change of key, iv
+            or similar after x amount of bytes enciphered
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher">
+            implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Basic constructor.
+            
+             @param cipher the block cipher to be used as the basis of chaining.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the cipher and, possibly, the initialisation vector (IV).
+             If an IV isn't passed as part of the parameter, the IV will be all zeros.
+            
+             @param 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.GetBlockSize">
+             return the block size of the underlying cipher.
+            
+             @return the block size of the underlying cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.Reset">
+            reset the chaining vector back to the IV and reset the underlying
+            cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             Do the appropriate chaining step for CBC mode encryption.
+            
+             @param in the array containing the data to be encrypted.
+             @param inOff offset into the in array the data starts at.
+             @param out the array the encrypted data will be copied into.
+             @param outOff the offset into the out array the output will start at.
+             @exception DataLengthException if there isn't enough data in in, or
+             space in out.
+             @exception InvalidOperationException if the cipher isn't initialised.
+             @return the number of bytes processed and produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             Do the appropriate chaining step for CBC mode decryption.
+            
+             @param in the array containing the data to be decrypted.
+             @param inOff offset into the in array the data starts at.
+             @param out the array the decrypted data will be copied into.
+             @param outOff the offset into the out array the output will start at.
+             @exception DataLengthException if there isn't enough data in in, or
+             space in out.
+             @exception InvalidOperationException if the cipher isn't initialised.
+             @return the number of bytes processed and produced.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.AlgorithmName">
+             return the algorithm name and mode.
+            
+             @return the name of the underlying algorithm followed by "/CBC".
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.CcmBlockCipher">
+                * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
+                * NIST Special Publication 800-38C.
+                * <p>
+                * <b>Note</b>: this mode is a packet mode - it needs all the data up front.
+            	* </p>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher">
+            <summary>
+            A block cipher mode that includes authenticated encryption with a streaming mode
+            and optional associated data.</summary>
+            <see cref="T:Org.BouncyCastle.Crypto.Parameters.AeadParameters"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            <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>
+            <param name="parameters">The key or other data required by the cipher.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.GetBlockSize">
+            <returns>The block size for this cipher, in bytes.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+             Encrypt/decrypt a single byte.
+            
+             @param input the byte to be processed.
+             @param outBytes the output buffer the processed byte goes into.
+             @param outOff the offset into the output byte array the processed data starts at.
+             @return the number of bytes written to out.
+             @exception DataLengthException if the output buffer is too small.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+             Process a block of bytes from in putting the result into out.
+            
+             @param inBytes 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 outBytes the output buffer the processed bytes go into.
+             @param outOff the offset into the output byte array the processed data starts at.
+             @return the number of bytes written to out.
+             @exception DataLengthException if the output buffer is too small.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.DoFinal(System.Byte[],System.Int32)">
+             Finish the operation either appending or verifying the MAC at the end of the data.
+            
+             @param outBytes space for any resulting output data.
+             @param outOff offset into out to start copying the data at.
+             @return number of bytes written into out.
+             @throws InvalidOperationException if the cipher is in an inappropriate state.
+             @throws InvalidCipherTextException if the MAC fails to match.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.GetMac">
+             Return the value of the MAC associated with the last stream processed.
+            
+             @return MAC for plaintext data.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.GetUpdateOutputSize(System.Int32)">
+             Return the size of the output buffer required for a ProcessBytes
+             an input of len bytes.
+            
+             @param len the length of the input.
+             @return the space required to accommodate a call to ProcessBytes
+             with len bytes of input.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.GetOutputSize(System.Int32)">
+             Return the size of the output buffer required for a ProcessBytes plus a
+             DoFinal with an input of len bytes.
+            
+             @param len the length of the input.
+             @return the space required to accommodate a call to ProcessBytes and DoFinal
+             with len bytes of input.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.Reset">
+            <summary>
+            Reset the cipher to the same state as it was after the last init (if there was one).
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.AlgorithmName">
+            <summary>The name of the algorithm this cipher implements.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CcmBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Basic constructor.
+            
+             @param cipher the block cipher to be used.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CcmBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CcmBlockCipher.GetMac">
+             Returns a byte array containing the mac calculated as part of the
+             last encrypt or decrypt operation.
+            
+             @return the last mac calculated.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher">
+            implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32)">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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 param the key and other data required by the cipher.
+             @exception ArgumentException if the parameters argument is
+             inappropriate.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.GetBlockSize">
+             return the block size we are operating at.
+            
+             @return the block size we are operating at (in bytes).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             Do the appropriate processing for CFB mode encryption.
+            
+             @param in the array containing the data to be encrypted.
+             @param inOff offset into the in array the data starts at.
+             @param out the array the encrypted data will be copied into.
+             @param outOff the offset into the out array the output will start at.
+             @exception DataLengthException if there isn't enough data in in, or
+             space in out.
+             @exception InvalidOperationException if the cipher isn't initialised.
+             @return the number of bytes processed and produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             Do the appropriate processing for CFB mode decryption.
+            
+             @param in the array containing the data to be decrypted.
+             @param inOff offset into the in array the data starts at.
+             @param out the array the encrypted data will be copied into.
+             @param outOff the offset into the out array the output will start at.
+             @exception DataLengthException if there isn't enough data in in, or
+             space in out.
+             @exception InvalidOperationException if the cipher isn't initialised.
+             @return the number of bytes processed and produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.Reset">
+            reset the chaining vector back to the IV and reset the underlying
+            cipher.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.AlgorithmName">
+             return the algorithm name and mode.
+            
+             @return the name of the underlying algorithm followed by "/CFB"
+             and the block size in bits.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Create a buffered block cipher that uses Cipher Text Stealing
+            
+             @param cipher the underlying block cipher this buffering object wraps.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher.GetUpdateOutputSize(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher.GetOutputSize(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher.DoFinal(System.Byte[],System.Int32)">
+             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).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.EaxBlockCipher">
+            A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and 
+            Efficiency - by M. Bellare, P. Rogaway, D. Wagner.
+            
+            http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
+            
+            EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block 
+            cipher to encrypt and authenticate data. It's on-line (the length of a 
+            message isn't needed to begin processing it), has good performances, it's
+            simple and provably secure (provided the underlying block cipher is secure).
+            
+            Of course, this implementations is NOT thread-safe.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.EaxBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Constructor that accepts an instance of a block cipher engine.
+            
+             @param cipher the engine to use
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.GcmBlockCipher">
+            <summary>
+            Implements the Galois/Counter mode (GCM) detailed in
+            NIST Special Publication 800-38D.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher">
+            implements the GOST 28147 OFB counter mode (GCTR).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Basic constructor.
+            
+             @param cipher the block cipher to be used as the basis of the
+             counter mode (must have a 64 bit block size).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the cipher and, possibly, the initialisation vector (IV).
+             If an IV isn't passed as part of the parameter, the IV will be all zeros.
+             An IV which is too short is handled in FIPS compliant fashion.
+            
+             @param encrypting if true the cipher is initialised for
+              encryption, if false for decryption.
+             @param parameters the key and other data required by the cipher.
+             @exception ArgumentException if the parameters argument is inappropriate.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.GetBlockSize">
+             return the block size we are operating at (in bytes).
+            
+             @return the block size we are operating at (in bytes).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.Reset">
+            reset the feedback vector back to the IV and reset the underlying
+            cipher.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.AlgorithmName">
+             return the algorithm name and mode.
+            
+             @return the name of the underlying algorithm followed by "/GCTR"
+             and the block size in bits
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher">
+            implements a Output-FeedBack (OFB) mode on top of a simple cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32)">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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 param the key and other data required by the cipher.
+             @exception ArgumentException if the parameters argument is
+             inappropriate.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.GetBlockSize">
+             return the block size we are operating at (in bytes).
+            
+             @return the block size we are operating at (in bytes).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.Reset">
+            reset the feedback vector back to the IV and reset the underlying
+            cipher.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.AlgorithmName">
+             return the algorithm name and mode.
+            
+             @return the name of the underlying algorithm followed by "/OFB"
+             and the block size in bits
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher">
+                * 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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Basic constructor.
+            
+             @param cipher the block cipher to be used as the basis of the
+             feedback mode.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.GetBlockSize">
+             return the block size we are operating at.
+            
+             @return the block size we are operating at (in bytes).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.Reset">
+            reset the chaining vector back to the IV and reset the underlying
+            cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.EncryptByte(System.Byte,System.Int32)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.AlgorithmName">
+             return the algorithm name and mode.
+            
+             @return the name of the underlying algorithm followed by "/PGPCFB"
+             and the block size in bits.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.SicBlockCipher">
+            Implements the Segmented Integer Counter (SIC) mode on top of a simple
+            block cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.SicBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Basic constructor.
+            
+             @param c the block cipher to be used.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.SicBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding">
+            Block cipher padders are expected to conform to this interface
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding.Init(Org.BouncyCastle.Security.SecureRandom)">
+             Initialise the padder.
+            
+             @param param parameters, if any required.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding.AddPadding(System.Byte[],System.Int32)">
+            add the pad bytes to the passed in block, returning the
+            number of bytes added.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding.PadCount(System.Byte[])">
+            return the number of pad bytes present in the block.
+            @exception InvalidCipherTextException if the padding is badly formed
+            or invalid.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding.PaddingName">
+             Return the name of the algorithm the cipher implements.
+            
+             @return the name of the algorithm the cipher implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.ISO10126d2Padding">
+            A padder that adds ISO10126-2 padding to a block.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ISO10126d2Padding.Init(Org.BouncyCastle.Security.SecureRandom)">
+             Initialise the padder.
+            
+             @param random a SecureRandom if available.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ISO10126d2Padding.AddPadding(System.Byte[],System.Int32)">
+            add the pad bytes to the passed in block, returning the
+            number of bytes added.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ISO10126d2Padding.PadCount(System.Byte[])">
+            return the number of pad bytes present in the block.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.ISO10126d2Padding.PaddingName">
+             Return the name of the algorithm the cipher implements.
+            
+             @return the name of the algorithm the cipher implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.ISO7816d4Padding">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ISO7816d4Padding.Init(Org.BouncyCastle.Security.SecureRandom)">
+             Initialise the padder.
+            
+             @param random - a SecureRandom if available.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ISO7816d4Padding.AddPadding(System.Byte[],System.Int32)">
+            add the pad bytes to the passed in block, returning the
+            number of bytes added.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ISO7816d4Padding.PadCount(System.Byte[])">
+            return the number of pad bytes present in the block.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.ISO7816d4Padding.PaddingName">
+             Return the name of the algorithm the padder implements.
+            
+             @return the name of the algorithm the padder implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+             Create a buffered block cipher with the desired padding.
+            
+             @param cipher the underlying block cipher this buffering object wraps.
+             @param padding the padding type.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Create a buffered block cipher Pkcs7 padding
+            
+             @param cipher the underlying block cipher this buffering object wraps.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.GetOutputSize(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.GetUpdateOutputSize(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.DoFinal(System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.Pkcs7Padding">
+            A padder that adds Pkcs7/Pkcs5 padding to a block.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.Pkcs7Padding.Init(Org.BouncyCastle.Security.SecureRandom)">
+             Initialise the padder.
+            
+             @param random - a SecureRandom if available.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.Pkcs7Padding.AddPadding(System.Byte[],System.Int32)">
+            add the pad bytes to the passed in block, returning the
+            number of bytes added.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.Pkcs7Padding.PadCount(System.Byte[])">
+            return the number of pad bytes present in the block.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.Pkcs7Padding.PaddingName">
+             Return the name of the algorithm the cipher implements.
+            
+             @return the name of the algorithm the cipher implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.TbcPadding">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.TbcPadding.Init(Org.BouncyCastle.Security.SecureRandom)">
+            <summary> Initialise the padder.</summary>
+            <param name="random">- a SecureRandom if available.
+            </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.TbcPadding.AddPadding(System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.TbcPadding.PadCount(System.Byte[])">
+            <summary> return the number of pad bytes present in the block.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.TbcPadding.PaddingName">
+            <summary> Return the name of the algorithm the cipher implements.</summary>
+            <returns> the name of the algorithm the cipher implements.
+            </returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.X923Padding">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.X923Padding.Init(Org.BouncyCastle.Security.SecureRandom)">
+             Initialise the padder.
+            
+             @param random a SecureRandom if one is available.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.X923Padding.AddPadding(System.Byte[],System.Int32)">
+            add the pad bytes to the passed in block, returning the
+            number of bytes added.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.X923Padding.PadCount(System.Byte[])">
+            return the number of pad bytes present in the block.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.X923Padding.PaddingName">
+             Return the name of the algorithm the cipher implements.
+            
+             @return the name of the algorithm the cipher implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.ZeroBytePadding">
+            <summary> A padder that adds Null byte padding to a block.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ZeroBytePadding.Init(Org.BouncyCastle.Security.SecureRandom)">
+             <summary> Initialise the padder.
+            
+             </summary>
+             <param name="random">- a SecureRandom if available.
+             </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ZeroBytePadding.AddPadding(System.Byte[],System.Int32)">
+            <summary> add the pad bytes to the passed in block, returning the
+            number of bytes added.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ZeroBytePadding.PadCount(System.Byte[])">
+            <summary> return the number of pad bytes present in the block.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.ZeroBytePadding.PaddingName">
+             <summary> Return the name of the algorithm the cipher implements.
+            
+             </summary>
+             <returns> the name of the algorithm the cipher implements.
+             </returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.AeadParameters.#ctor(Org.BouncyCastle.Crypto.Parameters.KeyParameter,System.Int32,System.Byte[],System.Byte[])">
+             Base constructor.
+            
+             @param key key to be used by underlying cipher
+             @param macSize macSize in bits
+             @param nonce nonce to be used
+             @param associatedText associated text, if any
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.CcmParameters.#ctor(Org.BouncyCastle.Crypto.Parameters.KeyParameter,System.Int32,System.Byte[],System.Byte[])">
+            Base constructor.
+            
+            @param key key to be used by underlying cipher
+            @param macSize macSize in bits
+            @param nonce nonce to be used
+            @param associatedText associated text, if any
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.DesParameters.IsWeakKey(System.Byte[],System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.DesParameters.SetOddParity(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.DesEdeParameters.IsWeakKey(System.Byte[],System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.DesEdeParameters.IsWeakKey(System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.DHParameters.M">
+            <summary>The minimum bitlength of the private value.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.DHParameters.L">
+            <summary>The bitlength of the private value.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.ElGamalParameters.G">
+            return the generator - g
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.ElGamalParameters.L">
+            return private value limit - l
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.IesParameters">
+            parameters for using an integrated cipher in stream mode.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.IesParameters.#ctor(System.Byte[],System.Byte[],System.Int32)">
+            @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).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.IesWithCipherParameters.#ctor(System.Byte[],System.Byte[],System.Int32,System.Int32)">
+            @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).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.Iso18033KdfParameters">
+            parameters for Key derivation functions for ISO-18033
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.KdfParameters">
+            parameters for Key derivation functions for IEEE P1363a
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.MgfParameters">
+            <remarks>Parameters for mask derivation functions.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyGenerationParameters">
+             Parameters for NaccacheStern public private key generation. For details on
+             this cipher, please see
+            
+             http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyGenerationParameters.#ctor(Org.BouncyCastle.Security.SecureRandom,System.Int32,System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyGenerationParameters.#ctor(Org.BouncyCastle.Security.SecureRandom,System.Int32,System.Int32,System.Int32,System.Boolean)">
+             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)
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyGenerationParameters.Certainty">
+            @return Returns the certainty.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyGenerationParameters.CountSmallPrimes">
+            @return Returns the countSmallPrimes.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyParameters">
+             Public key parameters for NaccacheStern cipher. For details on this cipher,
+             please see
+            
+             http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyParameters.#ctor(System.Boolean,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,System.Int32)">
+            @param privateKey
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyParameters.G">
+            @return Returns the g.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyParameters.LowerSigmaBound">
+            @return Returns the lowerSigmaBound.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyParameters.Modulus">
+            @return Returns the n.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.NaccacheSternPrivateKeyParameters">
+             Private key parameters for NaccacheStern cipher. For details on this cipher,
+             please see
+            
+             http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.NaccacheSternPrivateKeyParameters.#ctor(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,System.Int32,System.Collections.IList,Org.BouncyCastle.Math.BigInteger)">
+             Constructs a NaccacheSternPrivateKey
+            
+             @param g
+                        the public enryption parameter g
+             @param n
+                        the public modulus n = p*q
+             @param lowerSigmaBound
+                        the public lower sigma bound up to which data can be encrypted
+             @param smallPrimes
+                        the small primes, of which sigma is constructed in the right
+                        order
+             @param phi_n
+                        the private modulus phi(n) = (p-1)(q-1)
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.ParametersWithSalt">
+            <summary> Cipher parameters with a fixed salt value associated with them.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Prng.DigestRandomGenerator">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Prng.IRandomGenerator">
+            <remarks>Generic interface for objects generating random bytes.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.IRandomGenerator.AddSeedMaterial(System.Byte[])">
+            <summary>Add more seed material to the generator.</summary>
+            <param name="seed">A byte array to be mixed into the generator's state.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.IRandomGenerator.AddSeedMaterial(System.Int64)">
+            <summary>Add more seed material to the generator.</summary>
+            <param name="seed">A long value to be mixed into the generator's state.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.IRandomGenerator.NextBytes(System.Byte[])">
+            <summary>Fill byte array with random values.</summary>
+            <param name="bytes">Array to be filled.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.IRandomGenerator.NextBytes(System.Byte[],System.Int32,System.Int32)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Prng.ReversedWindowGenerator">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.ReversedWindowGenerator.AddSeedMaterial(System.Byte[])">
+            <summary>Add more seed material to the generator.</summary>
+            <param name="seed">A byte array to be mixed into the generator's state.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.ReversedWindowGenerator.AddSeedMaterial(System.Int64)">
+            <summary>Add more seed material to the generator.</summary>
+            <param name="seed">A long value to be mixed into the generator's state.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.ReversedWindowGenerator.NextBytes(System.Byte[])">
+            <summary>Fill byte array with random values.</summary>
+            <param name="bytes">Array to be filled.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.ReversedWindowGenerator.NextBytes(System.Byte[],System.Int32,System.Int32)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Prng.ThreadedSeedGenerator">
+            A thread based seed generator - one source of randomness.
+            <p>
+            Based on an idea from Marcus Lippert.
+            </p>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.ThreadedSeedGenerator.GenerateSeed(System.Int32,System.Boolean)">
+            Generate seed bytes. Set fast to false for best quality.
+            <p>
+            If fast is set to true, the code should be round about 8 times faster when
+            generating a long sequence of random bytes. 20 bytes of random values using
+            the fast mode take less than half a second on a Nokia e70. If fast is set to false,
+            it takes round about 2500 ms.
+            </p>
+            @param numBytes the number of bytes to generate
+            @param fast true if fast mode should be used
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Prng.VmpcRandomGenerator.P">
+            <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>
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Prng.VmpcRandomGenerator.s">
+            <remarks>Value generated in the same way as <c>P</c>.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaDigestSigner.Update(System.Byte)">
+            update the internal digest with the byte b
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaDigestSigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            update the internal digest with the byte array in
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaDigestSigner.GenerateSignature">
+            Generate a signature for the message we've been loaded with using
+            the key we were initialised with.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaDigestSigner.VerifySignature(System.Byte[])">
+            <returns>true if the internal state represents the signature described in the passed in array.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaDigestSigner.Reset">
+            <summary>Reset the internal state</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.DsaSigner">
+            The Digital Signature Algorithm - as described in "Handbook of Applied
+            Cryptography", pages 452 - 453.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaSigner.GenerateSignature(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaSigner.VerifySignature(System.Byte[],Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.ECDsaSigner">
+            EC-DSA as described in X9.62
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.ECDsaSigner.GenerateSignature(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.ECDsaSigner.VerifySignature(System.Byte[],Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.ECGost3410Signer">
+            GOST R 34.10-2001 Signature Algorithm
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.ECGost3410Signer.GenerateSignature(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.ECGost3410Signer.VerifySignature(System.Byte[],Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.ECNRSigner">
+            EC-NR as described in IEEE 1363-2000
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.ECNRSigner.GenerateSignature(System.Byte[])">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.ECNRSigner.VerifySignature(System.Byte[],Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.GenericSigner.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             initialise the signer for signing or verification.
+            
+             @param forSigning
+                        true if for signing, false otherwise
+             @param parameters
+                        necessary parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.GenericSigner.Update(System.Byte)">
+            update the internal digest with the byte b
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.GenericSigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            update the internal digest with the byte array in
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.GenericSigner.GenerateSignature">
+            Generate a signature for the message we've been loaded with using the key
+            we were initialised with.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.GenericSigner.VerifySignature(System.Byte[])">
+            return true if the internal state represents the signature described in
+            the passed in array.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410DigestSigner.Update(System.Byte)">
+            update the internal digest with the byte b
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410DigestSigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            update the internal digest with the byte array in
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410DigestSigner.GenerateSignature">
+            Generate a signature for the message we've been loaded with using
+            the key we were initialised with.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410DigestSigner.VerifySignature(System.Byte[])">
+            <returns>true if the internal state represents the signature described in the passed in array.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410DigestSigner.Reset">
+            <summary>Reset the internal state</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.Gost3410Signer">
+            Gost R 34.10-94 Signature Algorithm
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410Signer.GenerateSignature(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410Signer.VerifySignature(System.Byte[],Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.GetRecoveredMessage">
+            <summary>
+            Return a reference to the recoveredMessage message.
+            </summary>
+            <returns>The full/partial recoveredMessage message.</returns>
+            <seealso cref="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.GetRecoveredMessage"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher,Org.BouncyCastle.Crypto.IDigest,System.Int32,System.Boolean)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher,Org.BouncyCastle.Crypto.IDigest,System.Int32)">
+             <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            <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="T:System.ArgumentException">if wrong parameter type or a fixed
+            salt is passed in which is the wrong length.
+            </exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.IsSameAs(System.Byte[],System.Byte[])">
+            <summary> compare two byte arrays - constant time.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.ClearBlock(System.Byte[])">
+            <summary> clear possible sensitive data</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.Update(System.Byte)">
+            <summary> update the internal digest with the byte b</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            <summary> update the internal digest with the byte array in</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.Reset">
+            <summary> reset the internal state</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.GenerateSignature">
+            <summary> Generate a signature for the loaded message using the key we were
+            initialised with.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.VerifySignature(System.Byte[])">
+            <summary> return true if the signature represents a ISO9796-2 signature
+            for the passed in message.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.HasFullMessage">
+            <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="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.HasFullMessage"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.ItoOSP(System.Int32,System.Byte[])">
+            <summary> int to octet string.</summary>
+            <summary> int to octet string.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.LtoOSP(System.Int64,System.Byte[])">
+            <summary> long to octet string.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.MaskGeneratorFunction1(System.Byte[],System.Int32,System.Int32,System.Int32)">
+            <summary> mask generator function, as described in Pkcs1v2.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer">
+            <summary> ISO9796-2 - mechanism using a hash function with recovery (scheme 1)</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.GetRecoveredMessage">
+            <summary>
+            Return a reference to the recoveredMessage message.
+            </summary>
+            <returns>The full/partial recoveredMessage message.</returns>
+            <seealso cref="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.GetRecoveredMessage"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher,Org.BouncyCastle.Crypto.IDigest,System.Boolean)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher,Org.BouncyCastle.Crypto.IDigest)">
+             <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.IsSameAs(System.Byte[],System.Byte[])">
+            <summary> compare two byte arrays - constant time.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.ClearBlock(System.Byte[])">
+            <summary> clear possible sensitive data</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.Update(System.Byte)">
+            <summary> update the internal digest with the byte b</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            <summary> update the internal digest with the byte array in</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.Reset">
+            <summary> reset the internal state</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.GenerateSignature">
+            <summary> Generate a signature for the loaded message using the key we were
+            initialised with.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.VerifySignature(System.Byte[])">
+            <summary> return true if the signature represents a ISO9796-2 signature
+            for the passed in message.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.HasFullMessage">
+            <summary>
+            Return true if the full message was recoveredMessage.
+            </summary>
+            <returns> true on full message recovery, false otherwise.</returns>
+            <seealso cref="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.HasFullMessage"/>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.PssSigner">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher,Org.BouncyCastle.Crypto.IDigest,System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.ClearBlock(System.Byte[])">
+            <summary> clear possible sensitive data</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.Update(System.Byte)">
+            <summary> update the internal digest with the byte b</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            <summary> update the internal digest with the byte array in</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.Reset">
+            <summary> reset the internal state</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.GenerateSignature">
+            <summary> Generate a signature for the message we've been loaded with using
+            the key we were initialised with.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.VerifySignature(System.Byte[])">
+            <summary> return true if the internal state represents the signature described
+            in the passed in array.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.ItoOSP(System.Int32,System.Byte[])">
+            <summary> int to octet string.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.MaskGeneratorFunction1(System.Byte[],System.Int32,System.Int32,System.Int32)">
+            <summary> mask generator function, as described in Pkcs1v2.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.RsaDigestSigner.#cctor">
+            <summary>
+            Load oid table.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.RsaDigestSigner.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the signer for signing or verification.
+            
+             @param forSigning true if for signing, false otherwise
+             @param param necessary parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.RsaDigestSigner.Update(System.Byte)">
+            update the internal digest with the byte b
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.RsaDigestSigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            update the internal digest with the byte array in
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.RsaDigestSigner.GenerateSignature">
+            Generate a signature for the message we've been loaded with using
+            the key we were initialised with.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.RsaDigestSigner.VerifySignature(System.Byte[])">
+            return true if the internal state represents the signature described
+            in the passed in array.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.StreamBlockCipher">
+            a wrapper for block ciphers with a single byte block size, so that they
+            can be treated like stream ciphers.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.StreamBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             basic constructor.
+            
+             @param cipher the block cipher to be wrapped.
+             @exception ArgumentException if the cipher has a block size other than
+             one.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.StreamBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.StreamBlockCipher.ReturnByte(System.Byte)">
+             encrypt/decrypt a single byte returning the result.
+            
+             @param in the byte to be processed.
+             @return the result of processing the input byte.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.StreamBlockCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.StreamBlockCipher.Reset">
+            reset the underlying cipher. This leaves it in the same state
+            it was at after the last init (if there was one).
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.StreamBlockCipher.AlgorithmName">
+             return the name of the algorithm we are wrapping.
+            
+             @return the name of the algorithm we are wrapping.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.AlertDescription">
+            <summary>
+            RFC 2246 7.2
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.AlertLevel">
+            <summary>
+            RFC 2246 7.2
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.AlwaysValidVerifyer">
+            <remarks>
+            A certificate verifyer, that will always return true.
+            <pre>
+            DO NOT USE THIS FILE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING.
+            </pre>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ICertificateVerifyer">
+            <remarks>
+            This should be implemented by any class which can find out, if a given
+            certificate chain is being accepted by an client.
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.ICertificateVerifyer.IsValid(Org.BouncyCastle.Asn1.X509.X509CertificateStructure[])">
+            <param name="certs">The certs, which are part of the chain.</param>
+            <returns>True, if the chain is accepted, false otherwise</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.AlwaysValidVerifyer.IsValid(Org.BouncyCastle.Asn1.X509.X509CertificateStructure[])">
+            <summary>Return true.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ByteQueue">
+            <remarks>
+            A queue for bytes.
+            <p>
+            This file could be more optimized.
+            </p>
+            </remarks>
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ByteQueue.InitBufSize">
+            The initial size for our buffer.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.ByteQueue.NextTwoPow(System.Int32)">
+            <returns>The smallest number which can be written as 2^x which is bigger than i.</returns>
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ByteQueue.databuf">
+            The buffer where we store our data.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ByteQueue.skipped">
+            How many bytes at the beginning of the buffer are skipped.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ByteQueue.available">
+            How many bytes in the buffer are valid data.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.ByteQueue.Read(System.Byte[],System.Int32,System.Int32,System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.ByteQueue.AddData(System.Byte[],System.Int32,System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.ByteQueue.RemoveData(System.Int32)">
+            <summary>Remove some bytes from our data from the beginning.</summary>
+            <param name="i">How many bytes to remove.</param>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.ByteQueue.Available">
+            <summary>The number of bytes which are available in this buffer.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.Certificate">
+            A representation for a certificate chain.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.Certificate.certs">
+            The certificates.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.Certificate.Parse(System.IO.Stream)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.Certificate.Encode(System.IO.Stream)">
+             Encodes version of the ClientCertificate message
+            
+             @param outStr stream to write the message to
+             @throws IOException If something goes wrong
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.Certificate.#ctor(Org.BouncyCastle.Asn1.X509.X509CertificateStructure[])">
+             Private constructor from a cert array.
+            
+             @param certs The certs the chain should contain.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.Certificate.GetCerts">
+            <returns>An array which contains the certs, this chain contains.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.CertificateRequest.CertificateAuthorities">
+            <returns>A <see cref="T:System.Collections.IList"/> of X509Name</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.CipherSuite">
+            <summary>
+            RFC 2246 A.5
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ClientCertificateType">
+            <summary>
+            RFC 2246 7.4.4
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.CombinedHash">
+            <remarks>A combined hash, which implements md5(m) || sha1(m).</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.CombinedHash.GetByteLength">
+            <seealso cref="M:Org.BouncyCastle.Crypto.IDigest.GetByteLength"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.CombinedHash.GetDigestSize">
+            <seealso cref="M:Org.BouncyCastle.Crypto.IDigest.GetDigestSize"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.CombinedHash.Update(System.Byte)">
+            <seealso cref="M:Org.BouncyCastle.Crypto.IDigest.Update(System.Byte)"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.CombinedHash.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            <seealso cref="M:Org.BouncyCastle.Crypto.IDigest.BlockUpdate(System.Byte[],System.Int32,System.Int32)"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.CombinedHash.DoFinal(System.Byte[],System.Int32)">
+            <seealso cref="M:Org.BouncyCastle.Crypto.IDigest.DoFinal(System.Byte[],System.Int32)"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.CombinedHash.Reset">
+            <seealso cref="M:Org.BouncyCastle.Crypto.IDigest.Reset"/>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.CombinedHash.AlgorithmName">
+            <seealso cref="P:Org.BouncyCastle.Crypto.IDigest.AlgorithmName"/>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.CompressionMethod">
+            <summary>
+            RFC 2246 6.1
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ContentType">
+            <summary>
+            RFC 2246 6.2.1
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsAgreementCredentials.GenerateAgreement(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsCipherFactory.CreateCipher(Org.BouncyCastle.Crypto.Tls.TlsClientContext,Org.BouncyCastle.Crypto.Tls.EncryptionAlgorithm,Org.BouncyCastle.Crypto.Tls.DigestAlgorithm)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.DefaultTlsCipherFactory.CreateAesCipher(Org.BouncyCastle.Crypto.Tls.TlsClientContext,System.Int32,Org.BouncyCastle.Crypto.Tls.DigestAlgorithm)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.DefaultTlsCipherFactory.CreateDesEdeCipher(Org.BouncyCastle.Crypto.Tls.TlsClientContext,System.Int32,Org.BouncyCastle.Crypto.Tls.DigestAlgorithm)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.DefaultTlsCipherFactory.CreateDigest(Org.BouncyCastle.Crypto.Tls.DigestAlgorithm)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.Init(Org.BouncyCastle.Crypto.Tls.TlsClientContext)">
+            <summary>
+            Called at the start of a new TLS session, before any other methods.
+            </summary>
+            <param name="context">
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler"/>
+            </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetCipherSuites">
+            <summary>
+            Get the list of cipher suites that this client supports.
+            </summary>
+            <returns>
+            An array of <see cref="T:Org.BouncyCastle.Crypto.Tls.CipherSuite"/>, each specifying a supported cipher suite.
+            </returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetCompressionMethods">
+            <summary>
+            Get the list of compression methods that this client supports.
+            </summary>
+            <returns>
+            An array of <see cref="T:Org.BouncyCastle.Crypto.Tls.CompressionMethod"/>, each specifying a supported compression method.
+            </returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetClientExtensions">
+            <summary>
+            Get the (optional) table of client extensions to be included in (extended) client hello.
+            </summary>
+            <returns>
+            A <see cref="T:System.Collections.IDictionary"/> (<see cref="T:Org.BouncyCastle.Crypto.Tls.ExtensionType"/> -&gt; byte[]). May be null.
+            </returns>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.NotifySessionID(System.Byte[])">
+            <summary>
+            Reports the session ID once it has been determined.
+            </summary>
+            <param name="sessionID">
+            A <see cref="T:System.Byte"/>
+            </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.NotifySelectedCipherSuite(Org.BouncyCastle.Crypto.Tls.CipherSuite)">
+            <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="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetCipherSuites"/>
+            </remarks>
+            <param name="selectedCipherSuite">
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.CipherSuite"/>
+            </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.NotifySelectedCompressionMethod(Org.BouncyCastle.Crypto.Tls.CompressionMethod)">
+            <summary>
+            Report the compression method that was selected by the server.
+            </summary>
+            <remarks>
+            The protocol handler validates this value against the offered compression methods
+            <seealso cref="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetCompressionMethods"/>
+            </remarks>
+            <param name="selectedCompressionMethod">
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.CompressionMethod"/>
+            </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.NotifySecureRenegotiation(System.Boolean)">
+            <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="T:System.Boolean"/>, true if the server supports secure renegotiation
+            </param>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.ProcessServerExtensions(System.Collections.IDictionary)">
+            <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="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetClientExtensions"/>.
+            </remarks>
+            <param name="serverExtensions">
+            A <see cref="T:System.Collections.IDictionary"/>  (<see cref="T:Org.BouncyCastle.Crypto.Tls.ExtensionType"/> -&gt; byte[])
+            </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetKeyExchange">
+            <summary>
+            Return an implementation of <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange"/> to negotiate the key exchange
+            part of the protocol.
+            </summary>
+            <returns>
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange"/>
+            </returns>
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetAuthentication">
+            <summary>
+            Return an implementation of <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsAuthentication"/> to handle authentication
+            part of the protocol.
+            </summary>
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetCompression">
+            <summary>
+            Return an implementation of <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsCompression"/> to handle record compression.
+            </summary>
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetCipher">
+            <summary>
+            Return an implementation of <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsCipher"/> to use for encryption/decryption.
+            </summary>
+            <returns>
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsCipher"/>
+            </returns>
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsSignerCredentials.GenerateCertificateSignature(System.Byte[])">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ECCurveType">
+            <summary>
+            RFC 4492 5.4
+            </summary>
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ECCurveType.explicit_prime">
+            Indicates the elliptic curve domain parameters are conveyed verbosely, and the
+            underlying finite field is a prime field.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ECCurveType.explicit_char2">
+            Indicates the elliptic curve domain parameters are conveyed verbosely, and the
+            underlying finite field is a characteristic-2 field.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ECCurveType.named_curve">
+            Indicates that a named curve is used. This option SHOULD be used when applicable.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ECPointFormat">
+            <summary>
+            RFC 4492 5.1.2
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ExtensionType">
+            <summary>
+            RFC 4366 2.3
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.HandshakeType">
+            <summary>
+            RFC 2246 7.4
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.LegacyTlsAuthentication">
+            <summary>
+            A temporary class to wrap old CertificateVerifyer stuff for new TlsAuthentication.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsAuthentication.NotifyServerCertificate(Org.BouncyCastle.Crypto.Tls.Certificate)">
+            <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="T:Org.BouncyCastle.Crypto.Tls.Certificate"/> received</param>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsAuthentication.GetClientCredentials(Org.BouncyCastle.Crypto.Tls.CertificateRequest)">
+            <summary>
+            Return client credentials in response to server's certificate request
+            </summary>
+            <param name="certificateRequest">
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.CertificateRequest"/> containing server certificate request details
+            </param>
+            <returns>
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsCredentials"/> to be used for client authentication
+            (or <c>null</c> for no client authentication)
+            </returns>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.LegacyTlsClient">
+            <summary>
+            A temporary class to use LegacyTlsAuthentication 
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.NamedCurve">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.RecordStream">
+            <remarks>An implementation of the TLS 1.0 record layer.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.Ssl3Mac">
+            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))
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.Ssl3Mac.#ctor(Org.BouncyCastle.Crypto.IDigest)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.Ssl3Mac.Reset">
+            Reset the mac generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsBlockCipher">
+            <summary>
+            A generic TLS 1.0 block cipher. This can be used for AES or 3DES for example.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsCipher.EncodePlaintext(Org.BouncyCastle.Crypto.Tls.ContentType,System.Byte[],System.Int32,System.Int32)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsCipher.DecodeCiphertext(Org.BouncyCastle.Crypto.Tls.ContentType,System.Byte[],System.Int32,System.Int32)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsDHKeyExchange">
+            <summary>
+            TLS 1.0 DH key exchange.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange">
+            <summary>
+            A generic interface for key exchange implementations in TLS 1.0.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.SkipServerCertificate">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.ProcessServerCertificate(Org.BouncyCastle.Crypto.Tls.Certificate)">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.SkipServerKeyExchange">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.ProcessServerKeyExchange(System.IO.Stream)">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.ValidateCertificateRequest(Org.BouncyCastle.Crypto.Tls.CertificateRequest)">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.SkipClientCredentials">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.ProcessClientCredentials(Org.BouncyCastle.Crypto.Tls.TlsCredentials)">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.GenerateClientKeyExchange(System.IO.Stream)">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.GeneratePremasterSecret">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsECDheKeyExchange">
+            ECDHE key exchange (see RFC 4492)
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsECDHKeyExchange">
+            ECDH key exchange (see RFC 4492)
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsMac">
+            <remarks>
+            A generic TLS MAC implementation, which can be used with any kind of
+            IDigest to act as an HMAC.
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsMac.#ctor(Org.BouncyCastle.Crypto.IDigest,System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsMac.GetMacSecret">
+            @return the MAC write secret
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsMac.IncSequenceNumber">
+            Increment the current write sequence number
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsMac.CalculateMac(Org.BouncyCastle.Crypto.Tls.ContentType,System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.TlsMac.SequenceNumber">
+            @return the current write sequence number
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.TlsMac.Size">
+            @return The Keysize of the mac.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsNullCipher">
+            <summary>
+            A NULL cipher suite, for use during handshake.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler">
+            <remarks>An implementation of all high level protocols in TLS 1.0.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.#ctor(System.IO.Stream,System.IO.Stream)">
+            <remarks>Both streams can be the same object</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.#ctor(System.IO.Stream,System.IO.Stream,Org.BouncyCastle.Security.SecureRandom)">
+            <remarks>Both streams can be the same object</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.ProcessChangeCipherSpec">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.Connect(Org.BouncyCastle.Crypto.Tls.ICertificateVerifyer)">
+            <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="T:System.IO.IOException">If handshake was not successful</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.ReadApplicationData(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.WriteData(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.FailWithError(Org.BouncyCastle.Crypto.Tls.AlertLevel,Org.BouncyCastle.Crypto.Tls.AlertDescription)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.Close">
+            <summary>Closes this connection</summary>
+            <exception cref="T:System.IO.IOException">If something goes wrong during closing.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.AssertEmpty(System.IO.MemoryStream)">
+             Make sure the Stream is now empty. Fail otherwise.
+            
+             @param is The Stream to check.
+             @throws IOException If is is not empty.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.OutputStream">
+            <summary>A Stream which can be used to send data.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.InputStream">
+            <summary>A Stream which can be used to read data.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.Stream">
+            <summary>The secure bidirectional stream for this connection</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsRsaKeyExchange">
+            <summary>
+            TLS 1.0 RSA key exchange.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsSrpKeyExchange">
+            <summary>
+            TLS 1.1 SRP key exchange.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsUtilities">
+            <remarks>Some helper fuctions for MicroTLS.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.AddMagnitudes(System.Int32[],System.Int32[])">
+            return a = a + b - b preserved.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.CompareTo(System.Int32,System.Int32[],System.Int32,System.Int32[])">
+            unsigned comparison on two arrays - note the arrays may
+            start with leading zeros.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.Divide(System.Int32[],System.Int32[])">
+            return z = x / y - done in place (z value preserved, x contains the
+            remainder)
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.IsProbablePrime(System.Int32)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.ExtEuclid(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger@)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.Square(System.Int32[],System.Int32[])">
+            return w with w = x * x - w is assumed to have enough space.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.Multiply(System.Int32[],System.Int32[],System.Int32[])">
+            return x with x = y * z - x is assumed to have enough space.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.GetMQuote">
+            Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size)
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.MultiplyMonty(System.Int32[],System.Int32[],System.Int32[],System.Int32[],System.Int64)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.Remainder(System.Int32[],System.Int32[])">
+            return x = x % y - done in place (y value preserved)
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.ShiftLeft(System.Int32[],System.Int32)">
+            do a left shift - this returns a new array.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.ShiftRightInPlace(System.Int32,System.Int32[],System.Int32)">
+            do a right shift - this does it in place.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.ShiftRightOneInPlace(System.Int32,System.Int32[])">
+            do a right shift by one - this does it in place.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.Subtract(System.Int32,System.Int32[],System.Int32,System.Int32[])">
+            returns x = x - y - we assume x is >= y
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal.GetInstance(Org.BouncyCastle.Math.BigInteger,System.Int32)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal.#ctor(Org.BouncyCastle.Math.BigInteger,System.Int32)">
+            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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Abc.Tnaf">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.Tnaf.Width">
+            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
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.Tnaf.Pow2Width">
+            2<sup>4</sup>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.Tnaf.Alpha0">
+            The <code>&#945;<sub>u</sub></code>'s for <code>a=0</code> as an array
+            of <code>ZTauElement</code>s.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.Tnaf.Alpha0Tnaf">
+            The <code>&#945;<sub>u</sub></code>'s for <code>a=0</code> as an array
+            of TNAFs.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.Tnaf.Alpha1">
+            The <code>&#945;<sub>u</sub></code>'s for <code>a=1</code> as an array
+            of <code>ZTauElement</code>s.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.Tnaf.Alpha1Tnaf">
+            The <code>&#945;<sub>u</sub></code>'s for <code>a=1</code> as an array
+            of TNAFs.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.Norm(System.SByte,Org.BouncyCastle.Math.EC.Abc.ZTauElement)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.Norm(System.SByte,Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal,Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.Round(Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal,Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal,System.SByte)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.ApproximateDivisionByN(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,System.SByte,System.Int32,System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.TauAdicNaf(System.SByte,Org.BouncyCastle.Math.EC.Abc.ZTauElement)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.Tau(Org.BouncyCastle.Math.EC.F2mPoint)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.GetMu(Org.BouncyCastle.Math.EC.F2mCurve)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.GetLucas(System.SByte,System.Int32,System.Boolean)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.GetTw(System.SByte,System.Int32)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.GetSi(Org.BouncyCastle.Math.EC.F2mCurve)">
+            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).
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.PartModReduction(Org.BouncyCastle.Math.BigInteger,System.Int32,System.SByte,Org.BouncyCastle.Math.BigInteger[],System.SByte,System.SByte)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.MultiplyRTnaf(Org.BouncyCastle.Math.EC.F2mPoint,Org.BouncyCastle.Math.BigInteger)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.MultiplyTnaf(Org.BouncyCastle.Math.EC.F2mPoint,Org.BouncyCastle.Math.EC.Abc.ZTauElement)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.MultiplyFromTnaf(Org.BouncyCastle.Math.EC.F2mPoint,System.SByte[])">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.TauAdicWNaf(System.SByte,Org.BouncyCastle.Math.EC.Abc.ZTauElement,System.SByte,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.EC.Abc.ZTauElement[])">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.GetPreComp(Org.BouncyCastle.Math.EC.F2mPoint,System.SByte)">
+            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>. 
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Abc.ZTauElement">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.ZTauElement.u">
+            The &quot;real&quot; part of <code>&#955;</code>.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.ZTauElement.v">
+            The &quot;<code>&#964;</code>-adic&quot; part of <code>&#955;</code>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.ZTauElement.#ctor(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.ECCurve">
+            <remarks>Base class for an elliptic curve.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.ECCurveBase.DecodePoint(System.Byte[])">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.FpCurve">
+            Elliptic curve over Fp
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.F2mCurve">
+            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>.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.m">
+            The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.k1">
+            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/>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.k2">
+            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/>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.k3">
+            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/>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.n">
+            The order of the base point of the curve.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.h">
+            The cofactor of the curve.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.infinity">
+            The point at infinity on this curve.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.mu">
+            The parameter <code>&#956;</code> of the elliptic curve if this is
+            a Koblitz curve.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.si">
+            The auxiliary values <code>s<sub>0</sub></code> and
+            <code>s<sub>1</sub></code> used for partial modular reduction for
+            Koblitz curves.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.#ctor(System.Int32,System.Int32,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.#ctor(System.Int32,System.Int32,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.GetMu">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.GetSi">
+            @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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.solveQuadradicEquation(Org.BouncyCastle.Math.EC.ECFieldElement)">
+             Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+             D.1.6) The other solution is <code>z + 1</code>.
+            
+             @param beta
+                        The value to solve the qradratic equation for.
+             @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+                     <code>null</code> if no solution exists.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.IsTrinomial">
+             Return true if curve uses a Trinomial basis.
+            
+             @return true if curve Trinomial, false otherwise.
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.F2mCurve.IsKoblitz">
+            Returns true if this is a Koblitz curve (ABC curve).
+            @return true if this is a Koblitz curve (ABC curve), false otherwise
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.FpFieldElement.Sqrt">
+            return a sqrt root - the routine verifies that the calculation
+            returns the right value - if none exists it returns null.
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.FpFieldElement.FieldName">
+             return the field name for this field.
+            
+             @return the string "Fp".
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.F2mFieldElement">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.Gnb">
+            Indicates gaussian normal basis representation (GNB). Number chosen
+            according to X9.62. GNB is not implemented at present.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.Tpb">
+            Indicates trinomial basis representation (Tpb). Number chosen
+            according to X9.62.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.Ppb">
+            Indicates pentanomial basis representation (Ppb). Number chosen
+            according to X9.62.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.representation">
+            Tpb or Ppb.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.m">
+            The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.k1">
+            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/>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.k2">
+            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/>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.k3">
+            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/>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.x">
+            The <code>IntArray</code> holding the bits.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.t">
+            The number of <code>int</code>s required to hold <code>m</code> bits.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mFieldElement.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,Org.BouncyCastle.Math.BigInteger)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mFieldElement.#ctor(System.Int32,System.Int32,Org.BouncyCastle.Math.BigInteger)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mFieldElement.CheckFieldElements(Org.BouncyCastle.Math.EC.ECFieldElement,Org.BouncyCastle.Math.EC.ECFieldElement)">
+            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).
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.F2mFieldElement.Representation">
+            @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).
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.F2mFieldElement.M">
+            @return the degree <code>m</code> of the reduction polynomial
+            <code>f(z)</code>.
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.F2mFieldElement.K1">
+            @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/>
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.F2mFieldElement.K2">
+            @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/>
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.F2mFieldElement.K3">
+            @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/>
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.ECPoint">
+            base class for points on elliptic curves.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.ECPoint.SetPreCompInfo(Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.ECPoint.AssertECMultiplier">
+            Sets the appropriate <code>ECMultiplier</code>, unless already set. 
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.ECPointBase.GetEncoded">
+            return the field element encoded with point compression. (S 4.3.6)
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.ECPointBase.Multiply(Org.BouncyCastle.Math.BigInteger)">
+            Multiplies this <code>ECPoint</code> by the given number.
+            @param k The multiplicator.
+            @return <code>k * this</code>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.FpPoint">
+            Elliptic curve points over Fp
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.FpPoint.#ctor(Org.BouncyCastle.Math.EC.ECCurve,Org.BouncyCastle.Math.EC.ECFieldElement,Org.BouncyCastle.Math.EC.ECFieldElement)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.FpPoint.#ctor(Org.BouncyCastle.Math.EC.ECCurve,Org.BouncyCastle.Math.EC.ECFieldElement,Org.BouncyCastle.Math.EC.ECFieldElement,System.Boolean)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.FpPoint.AssertECMultiplier">
+            Sets the default <code>ECMultiplier</code>, unless already set. 
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.F2mPoint">
+            Elliptic curve points over F2m
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.#ctor(Org.BouncyCastle.Math.EC.ECCurve,Org.BouncyCastle.Math.EC.ECFieldElement,Org.BouncyCastle.Math.EC.ECFieldElement)">
+            @param curve base curve
+            @param x x point
+            @param y y point
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.#ctor(Org.BouncyCastle.Math.EC.ECCurve,Org.BouncyCastle.Math.EC.ECFieldElement,Org.BouncyCastle.Math.EC.ECFieldElement,System.Boolean)">
+            @param curve base curve
+            @param x x point
+            @param y y point
+            @param withCompression true if encode with point compression.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.#ctor(Org.BouncyCastle.Math.EC.ECCurve)">
+            Constructor for point at infinity
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.CheckPoints(Org.BouncyCastle.Math.EC.ECPoint,Org.BouncyCastle.Math.EC.ECPoint)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.AddSimple(Org.BouncyCastle.Math.EC.F2mPoint)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.SubtractSimple(Org.BouncyCastle.Math.EC.F2mPoint)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.AssertECMultiplier">
+            Sets the appropriate <code>ECMultiplier</code>, unless already set. 
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.ECMultiplier">
+            Interface for classes encapsulating a point multiplication algorithm
+            for <code>ECPoint</code>s.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.ECMultiplier.Multiply(Org.BouncyCastle.Math.EC.ECPoint,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo)">
+            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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.FpNafMultiplier">
+            Class implementing the NAF (Non-Adjacent Form) multiplication algorithm.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.FpNafMultiplier.Multiply(Org.BouncyCastle.Math.EC.ECPoint,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo)">
+            D.3.2 pg 101
+            @see org.bouncycastle.math.ec.multiplier.ECMultiplier#multiply(org.bouncycastle.math.ec.ECPoint, java.math.BigInteger)
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo">
+            Interface for classes storing precomputation data for multiplication
+            algorithms. Used as a Memento (see GOF patterns) for
+            <code>WNafMultiplier</code>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.ReferenceMultiplier.Multiply(Org.BouncyCastle.Math.EC.ECPoint,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo)">
+            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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.WNafMultiplier">
+            Class implementing the WNAF (Window Non-Adjacent Form) multiplication
+            algorithm.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WNafMultiplier.WindowNaf(System.SByte,Org.BouncyCastle.Math.BigInteger)">
+            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 = &#8722;<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>sbyte[]</code>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WNafMultiplier.Multiply(Org.BouncyCastle.Math.EC.ECPoint,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo)">
+            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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.WNafPreCompInfo">
+            Class holding precomputation data for the WNAF (Window Non-Adjacent Form)
+            algorithm.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Multiplier.WNafPreCompInfo.preComp">
+            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>.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Multiplier.WNafPreCompInfo.twiceP">
+            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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.WTauNafMultiplier">
+            Class implementing the WTNAF (Window
+            <code>&#964;</code>-adic Non-Adjacent Form) algorithm.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WTauNafMultiplier.Multiply(Org.BouncyCastle.Math.EC.ECPoint,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WTauNafMultiplier.MultiplyWTnaf(Org.BouncyCastle.Math.EC.F2mPoint,Org.BouncyCastle.Math.EC.Abc.ZTauElement,Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo,System.SByte,System.SByte)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WTauNafMultiplier.MultiplyFromWTnaf(Org.BouncyCastle.Math.EC.F2mPoint,System.SByte[],Org.BouncyCastle.Math.EC.Multiplier.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>
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.WTauNafPreCompInfo">
+            Class holding precomputation data for the WTNAF (Window
+            <code>&#964;</code>-adic Non-Adjacent Form) algorithm.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Multiplier.WTauNafPreCompInfo.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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WTauNafPreCompInfo.#ctor(Org.BouncyCastle.Math.EC.F2mPoint[])">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WTauNafPreCompInfo.GetPreComp">
+            @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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.BasicOcspResp">
+            <remarks>
+            <code>
+            BasicOcspResponse ::= SEQUENCE {
+            	tbsResponseData		ResponseData,
+            	signatureAlgorithm	AlgorithmIdentifier,
+            	signature			BIT STRING,
+            	certs				[0] EXPLICIT SEQUENCE OF Certificate OPTIONAL
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.IX509Extension.GetCriticalExtensionOids">
+            <summary>
+            Get all critical extension values, by oid
+            </summary>
+            <returns>IDictionary with string (OID) keys and Asn1OctetString values</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.IX509Extension.GetNonCriticalExtensionOids">
+            <summary>
+            Get all non-critical extension values, by oid
+            </summary>
+            <returns>IDictionary with string (OID) keys and Asn1OctetString values</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509ExtensionBase.GetNonCriticalExtensionOids">
+            <summary>
+            Get non critical extensions.
+            </summary>
+            <returns>A set of non critical extension oids.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509ExtensionBase.GetCriticalExtensionOids">
+            <summary>
+            Get any critical extensions.
+            </summary>
+            <returns>A sorted list of critical entension.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509ExtensionBase.GetExtensionValue(System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspResp.GetTbsResponseData">
+            <returns>The DER encoding of the tbsResponseData field.</returns>
+            <exception cref="T:Org.BouncyCastle.Ocsp.OcspException">In the event of an encoding error.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspResp.GetCertificates(System.String)">
+            <returns>The certificates, if any, associated with the response.</returns>
+            <exception cref="T:Org.BouncyCastle.Ocsp.OcspException">In the event of an encoding error.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspResp.Verify(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <summary>
+            Verify the signature against the tbsResponseData object we contain.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspResp.GetEncoded">
+            <returns>The ASN.1 encoded representation of this object.</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator">
+            Generator for basic OCSP response objects.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.#ctor(Org.BouncyCastle.Ocsp.RespID)">
+            basic constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            construct with the responderID to be the SHA-1 keyHash of the passed in public key.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.AddResponse(Org.BouncyCastle.Ocsp.CertificateID,Org.BouncyCastle.Ocsp.CertificateStatus)">
+             Add a response for a particular Certificate ID.
+            
+             @param certID certificate ID details
+             @param certStatus status of the certificate - null if okay
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.AddResponse(Org.BouncyCastle.Ocsp.CertificateID,Org.BouncyCastle.Ocsp.CertificateStatus,Org.BouncyCastle.Asn1.X509.X509Extensions)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.AddResponse(Org.BouncyCastle.Ocsp.CertificateID,Org.BouncyCastle.Ocsp.CertificateStatus,System.DateTime,Org.BouncyCastle.Asn1.X509.X509Extensions)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.AddResponse(Org.BouncyCastle.Ocsp.CertificateID,Org.BouncyCastle.Ocsp.CertificateStatus,System.DateTime,System.DateTime,Org.BouncyCastle.Asn1.X509.X509Extensions)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.SetResponseExtensions(Org.BouncyCastle.Asn1.X509.X509Extensions)">
+             Set the extensions for the response.
+            
+             @param responseExtensions the extension object to carry.
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.SignatureAlgNames">
+             Return an IEnumerable of the signature names supported by the generator.
+            
+             @return an IEnumerable containing recognised names.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.CertificateID.#ctor(System.String,Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Math.BigInteger)">
+            create from an issuer certificate and the serial number of the
+            certificate it signed.
+            @exception OcspException if any problems occur creating the id fields.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.CertificateID.DeriveCertificateID(Org.BouncyCastle.Ocsp.CertificateID,Org.BouncyCastle.Math.BigInteger)">
+             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
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.CertificateID.SerialNumber">
+            return the serial number for the certificate associated
+            with this request.
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.OcspReq">
+             <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReq.GetTbsRequest">
+            Return the DER encoding of the tbsRequest field.
+            @return DER encoding of tbsRequest
+            @throws OcspException in the event of an encoding error.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReq.GetCertificates(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReq.Verify(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            Verify the signature against the TBSRequest object we contain.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReq.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.OcspReq.SignatureAlgOid">
+            return the object identifier representing the signature algorithm
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.OcspReq.IsSigned">
+             Return whether or not this request is signed.
+            
+             @return true if signed false otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReqGenerator.AddRequest(Org.BouncyCastle.Ocsp.CertificateID)">
+             Add a request for the given CertificateID.
+            
+             @param certId certificate ID of interest
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReqGenerator.AddRequest(Org.BouncyCastle.Ocsp.CertificateID,Org.BouncyCastle.Asn1.X509.X509Extensions)">
+             Add a request with extensions
+            
+             @param certId certificate ID of interest
+             @param singleRequestExtensions the extensions to attach to the request
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReqGenerator.SetRequestorName(Org.BouncyCastle.Asn1.X509.X509Name)">
+             Set the requestor name to the passed in X509Principal
+            
+             @param requestorName a X509Principal representing the requestor name.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReqGenerator.Generate">
+             Generate an unsigned request
+            
+             @return the OcspReq
+             @throws OcspException
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.OcspReqGenerator.SignatureAlgNames">
+             Return an IEnumerable of the signature names supported by the generator.
+            
+             @return an IEnumerable containing recognised names.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspResp.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.OCSPRespGenerator">
+            base generator for an OCSP response - at the moment this only supports the
+            generation of responses containing BasicOCSP responses.
+        </member>
+        <member name="F:Org.BouncyCastle.Ocsp.OcspRespStatus.Successful">
+            note 4 is not used.
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.RespID">
+            Carrier for a ResponderID.
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.RevokedStatus">
+            wrapper for the RevokedInfo object
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.RevokedStatus.RevocationReason">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.SingleResp.GetCertStatus">
+             Return the status object for the response - null indicates good.
+            
+             @return the status object for the response, null if it is good.
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.SingleResp.NextUpdate">
+             return the NextUpdate value - note: this is an optional field so may
+             be returned as null.
+            
+             @return nextUpdate, or null if not present.
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.UnknownStatus">
+            wrapper for the UnknownInfo object
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedData">
+            <remarks>Compressed data objects</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedData.GetInputStream">
+            <summary>Get the raw input stream contained in the object.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedData.GetDataStream">
+            <summary>Return an uncompressed input stream which allows reading of the compressed data.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedData.Algorithm">
+            <summary>The algorithm used for compression</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedDataGenerator">
+            <remarks>Class for producing compressed data packets.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedDataGenerator.Open(System.IO.Stream)">
+            <summary>
+            <p>
+            Return an output stream which will save the data being written to
+            the compressed object.
+            </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>
+            <param name="outStr">Stream to be used for output.</param>
+            <returns>A Stream for output of the compressed data.</returns>
+            <exception cref="T:System.ArgumentNullException"></exception>
+            <exception cref="T:System.InvalidOperationException"></exception>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedDataGenerator.Open(System.IO.Stream,System.Byte[])">
+            <summary>
+            <p>
+            Return an output stream which will compress 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>
+            <p>
+            <b>Note</b>: using this may break compatibility with RFC 1991 compliant tools.
+            Only recent OpenPGP implementations are capable of accepting these streams.
+            </p>
+            </summary>
+            <param name="outStr">Stream to be used for output.</param>
+            <param name="buffer">The buffer to use.</param>
+            <returns>A Stream for output of the compressed data.</returns>
+            <exception cref="T:System.ArgumentNullException"></exception>
+            <exception cref="T:System.InvalidOperationException"></exception>
+            <exception cref="T:System.IO.IOException"></exception>
+            <exception cref="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedDataGenerator.Close">
+            <summary>Close the compressed object.</summary>summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpDataValidationException">
+            <remarks>
+            Thrown if the IV at the start of a data stream indicates the wrong key is being used.
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException">
+            <remarks>Generic exception class for PGP encoding/decoding problems.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedData.GetInputStream">
+            <summary>Return the raw input stream for the data stream.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedData.IsIntegrityProtected">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedData.Verify">
+            <summary>Note: This can only be called after the message has been read.</summary>
+            <returns>True, if the message verifies, false otherwise</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator">
+            <remarks>Generator for encrypted objects.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.#ctor(Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Existing SecureRandom constructor.</summary>
+            <param name="encAlgorithm">The symmetric algorithm to use.</param>
+            <param name="rand">Source of randomness.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.#ctor(Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,System.Boolean,Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Creates a cipher stream which will have an integrity packet associated with it.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.#ctor(Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,Org.BouncyCastle.Security.SecureRandom,System.Boolean)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.AddMethod(System.Char[])">
+            <summary>
+            Add a PBE encryption method to the encrypted object using the default algorithm (S2K_SHA1).
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.AddMethod(System.Char[],Org.BouncyCastle.Bcpg.HashAlgorithmTag)">
+            <summary>Add a PBE encryption method to the encrypted object.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.AddMethod(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Add a public key encrypted session key to the encrypted object.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.Open(System.IO.Stream,System.Int64,System.Byte[])">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.Open(System.IO.Stream,System.Int64)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.Open(System.IO.Stream,System.Byte[])">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.Close">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataList">
+            <remarks>A holder for a list of PGP encryption method packets.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyFlags">
+            <remarks>Key flag values for the KeyFlags subpacket.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair.#ctor(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair.KeyId">
+            <summary>The keyId associated with this key pair.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator">
+            <remarks>
+            Generator for a PGP master and subkey ring.
+            This class will generate both the secret and public key rings
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator.#ctor(System.Int32,Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair,System.String,Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,System.Char[],Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator.#ctor(System.Int32,Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair,System.String,Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,System.Char[],System.Boolean,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator.AddSubKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair)">
+            <summary>Add a subkey to the key ring to be generated with default certification.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator.AddSubKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector)">
+            <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="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator.GenerateSecretKeyRing">
+            <summary>Return the secret key ring.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator.GeneratePublicKeyRing">
+            <summary>Return the public key ring that corresponds to the secret key ring.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyValidationException">
+            <remarks>
+            Thrown if the key checksum is invalid.
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData">
+            <summary>Class for processing literal data objects.</summary>
+        </member>
+        <member name="F:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.Console">
+            <summary>The special name indicating a "for your eyes only" packet.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.GetRawFileName">
+            Return the file name as an unintrepreted byte array.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.GetInputStream">
+            <summary>The raw input stream for the data stream.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.GetDataStream">
+            <summary>The input stream representing the data stream.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.Format">
+            <summary>The format of the data stream - Binary or Text</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.FileName">
+            <summary>The file name that's associated with the data stream.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.ModificationTime">
+            <summary>The modification time for the file.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralDataGenerator">
+            <remarks>Class for producing literal data packets.</remarks>
+        </member>
+        <member name="F:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralDataGenerator.Console">
+            <summary>The special name indicating a "for your eyes only" packet.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralDataGenerator.#ctor(System.Boolean)">
+            <summary>
+            Generates literal data objects in the old format.
+            This is important if you need compatibility with PGP 2.6.x.
+            </summary>
+            <param name="oldFormat">If true, uses old format.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralDataGenerator.Open(System.IO.Stream,System.Char,System.String,System.Int64,System.DateTime)">
+            <summary>
+            <p>
+            Open a literal data packet, returning a stream to store the data inside the 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>
+            <param name="outStr">The stream we want the packet in.</param>
+            <param name="format">The format we are using.</param>
+            <param name="name">The name of the 'file'.</param>
+            <param name="length">The length of the data we will write.</param>
+            <param name="modificationTime">The time of last modification we want stored.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralDataGenerator.Open(System.IO.Stream,System.Char,System.String,System.DateTime,System.Byte[])">
+            <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
+            packets with a chunk size determined by 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>
+            <param name="outStr">The stream we want the packet in.</param>
+            <param name="format">The format we are using.</param>
+            <param name="name">The name of the 'file'.</param>
+            <param name="modificationTime">The time of last modification we want stored.</param>
+            <param name="buffer">The buffer to use for collecting data to put into chunks.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralDataGenerator.Close">
+            <summary>
+            Close the literal data packet - this is equivalent to calling Close()
+            on the stream returned by the Open() method.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpMarker">
+            <remarks>
+            A PGP marker packet - in general these should be ignored other than where
+            the idea is to preserve the original input stream.
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpObjectFactory">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpObjectFactory.NextPgpObject">
+            <summary>Return the next object in the stream, or null if the end is reached.</summary>
+            <exception cref="T:System.IO.IOException">On a parse error</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpObjectFactory.AllPgpObjects">
+            <summary>
+            Return all available objects in a list.
+            </summary>
+            <returns>An <c>IList</c> containing all objects from this factory, in order.</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpOnePassSignature">
+            <remarks>A one pass signature object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpOnePassSignature.InitVerify(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Initialise the signature object for verification.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpOnePassSignature.Verify(Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <summary>Verify the calculated signature against the passed in PgpSignature.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpOnePassSignatureList">
+            <remarks>Holder for a list of PgpOnePassSignature objects.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpPbeEncryptedData">
+            <remarks>A password based encryption object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPbeEncryptedData.GetInputStream">
+            <summary>Return the raw input stream for the data stream.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPbeEncryptedData.GetDataStream(System.Char[])">
+            <summary>Return the decrypted input stream, using the passed in passphrase.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey">
+            <remarks>General class to contain a private key for use with other OpenPGP objects.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Int64)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey.KeyId">
+            <summary>The keyId associated with the contained private key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey.Key">
+            <summary>The contained private key.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey">
+            <remarks>General class to handle a PGP public key object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.#ctor(Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.DateTime)">
+            <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="T:System.ArgumentException">If <c>pubKey</c> is not public.</exception>
+            <exception cref="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException">On key creation problem.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.#ctor(Org.BouncyCastle.Bcpg.PublicKeyPacket,Org.BouncyCastle.Bcpg.TrustPacket,System.Collections.IList)">
+            <summary>Constructor for a sub-key.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.#ctor(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Copy constructor.</summary>
+            <param name="pubKey">The public key to copy.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetTrustData">
+            <summary>Return the trust data associated with the public key, if present.</summary>
+            <returns>A byte array with trust data, null otherwise.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetValidSeconds">
+            <summary>The number of valid seconds from creation time - zero means no expiry.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetFingerprint">
+            <summary>The fingerprint of the key</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetKey">
+            <summary>The public key contained in the object.</summary>
+            <returns>A lightweight public key.</returns>
+            <exception cref="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException">If the key algorithm is not recognised.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetUserIds">
+            <summary>Allows enumeration of any user IDs associated with the key.</summary>
+            <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetUserAttributes">
+            <summary>Allows enumeration of any user attribute vectors associated with the key.</summary>
+            <returns>An <c>IEnumerable</c> of <c>PgpUserAttributeSubpacketVector</c> objects.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetSignaturesForId(System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetSignaturesForUserAttribute(Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetSignaturesOfType(System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetSignatures">
+            <summary>Allows enumeration of all signatures/certifications associated with this key.</summary>
+            <returns>An <c>IEnumerable</c> with all signatures/certifications.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.IsRevoked">
+            <summary>Check whether this (sub)key has a revocation signature on it.</summary>
+            <returns>True, if this (sub)key has been revoked.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.AddCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,System.String,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.AddCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.RemoveCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.RemoveCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.RemoveCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,System.String,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.RemoveCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.AddCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.RemoveCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.Version">
+            <summary>The version of this key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.CreationTime">
+            <summary>The creation time of this key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.ValidDays">
+            <summary>The number of valid days from creation time - zero means no expiry.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.KeyId">
+            <summary>The keyId associated with the public key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.IsEncryptionKey">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.IsMasterKey">
+            <summary>True, if this is a master key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.Algorithm">
+            <summary>The algorithm code associated with the public key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.BitStrength">
+            <summary>The strength of the key in bits.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyEncryptedData">
+            <remarks>A public key encrypted data object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyEncryptedData.GetSymmetricAlgorithm(Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey)">
+            <summary>
+            Return the algorithm code for the symmetric algorithm used to encrypt the data.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyEncryptedData.GetDataStream(Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey)">
+            <summary>Return the decrypted data stream for the packet.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyEncryptedData.KeyId">
+            <summary>The key ID for the key used to encrypt the data.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing.GetPublicKey">
+            <summary>Return the first public key in the ring.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing.GetPublicKey(System.Int64)">
+            <summary>Return the public key referred to by the passed in key ID if it is present.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing.GetPublicKeys">
+            <summary>Allows enumeration of all the public keys.</summary>
+            <returns>An <c>IEnumerable</c> of <c>PgpPublicKey</c> objects.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing.InsertPublicKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing.RemovePublicKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle">
+            <remarks>
+            Often a PGP key ring file is made up of a succession of master/sub-key key rings.
+            If you want to read an entire public key file in one hit this is the class for you.
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.#ctor(System.IO.Stream)">
+            <summary>Build a PgpPublicKeyRingBundle from the passed in input stream.</summary>
+            <param name="inputStream">Input stream containing data.</param>
+            <exception cref="T:System.IO.IOException">If a problem parsing the stream occurs.</exception>
+            <exception cref="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException">If an object is encountered which isn't a PgpPublicKeyRing.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.GetKeyRings">
+            <summary>Allow enumeration of the public key rings making up this collection.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.GetKeyRings(System.String)">
+            <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+            <param name="userId">The user ID to be matched.</param>
+            <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.GetKeyRings(System.String,System.Boolean)">
+            <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+            <param name="userId">The user ID to be matched.</param>
+            <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+            <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.GetKeyRings(System.String,System.Boolean,System.Boolean)">
+            <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+            <param name="userId">The user ID to be matched.</param>
+            <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+            <param name="ignoreCase">If true, case is ignored in user ID comparisons.</param>
+            <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.GetPublicKey(System.Int64)">
+            <summary>Return the PGP public key associated with the given key id.</summary>
+            <param name="keyId">The ID of the public key to return.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.GetPublicKeyRing(System.Int64)">
+            <summary>Return the public key ring which contains the key referred to by keyId</summary>
+            <param name="keyId">key ID to match against</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.Contains(System.Int64)">
+            <summary>
+            Return true if a key matching the passed in key ID is present, false otherwise.
+            </summary>
+            <param name="keyID">key ID to look for.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.AddPublicKeyRing(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing)">
+            <summary>
+            Return a new bundle containing the contents of the passed in bundle and
+            the passed in public key ring.
+            </summary>
+            <param name="bundle">The <c>PgpPublicKeyRingBundle</c> the key ring is to be added to.</param>
+            <param name="publicKeyRing">The key ring to be added.</param>
+            <returns>A new <c>PgpPublicKeyRingBundle</c> merging the current one with the passed in key ring.</returns>
+            <exception cref="T:System.ArgumentException">If the keyId for the passed in key ring is already present.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.RemovePublicKeyRing(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing)">
+            <summary>
+            Return a new bundle containing the contents of the passed in bundle with
+            the passed in public key ring removed.
+            </summary>
+            <param name="bundle">The <c>PgpPublicKeyRingBundle</c> the key ring is to be removed from.</param>
+            <param name="publicKeyRing">The key ring to be removed.</param>
+            <returns>A new <c>PgpPublicKeyRingBundle</c> not containing the passed in key ring.</returns>
+            <exception cref="T:System.ArgumentException">If the keyId for the passed in key ring is not present.</exception>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.Count">
+            <summary>Return the number of key rings in this collection.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey">
+            <remarks>General class to handle a PGP secret key object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.ExtractPrivateKey(System.Char[])">
+            <summary>Extract a <c>PgpPrivateKey</c> from this secret key's encrypted contents.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.CopyWithNewPassword(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey,System.Char[],System.Char[],Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.ReplacePublicKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <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="T:System.ArgumentException">If KeyId's do not match.</exception>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.IsSigningKey">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.IsMasterKey">
+            <summary>True, if this is a master key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.KeyEncryptionAlgorithm">
+            <summary>The algorithm the key is encrypted with.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.KeyId">
+            <summary>The key ID of the public key associated with this key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.PublicKey">
+            <summary>The public key associated with this key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.UserIds">
+            <summary>Allows enumeration of any user IDs associated with the key.</summary>
+            <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.UserAttributes">
+            <summary>Allows enumeration of any user attribute vectors associated with the key.</summary>
+            <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.GetPublicKey">
+            <summary>Return the public key for the master key.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.GetSecretKey">
+            <summary>Return the master private key.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.GetSecretKeys">
+            <summary>Allows enumeration of the secret keys.</summary>
+            <returns>An <c>IEnumerable</c> of <c>PgpSecretKey</c> objects.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.GetExtraPublicKeys">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.ReplacePublicKeys(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.CopyWithNewPassword(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing,System.Char[],System.Char[],Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.InsertSecretKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing,Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.RemoveSecretKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing,Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle">
+            <remarks>
+            Often a PGP key ring file is made up of a succession of master/sub-key key rings.
+            If you want to read an entire secret key file in one hit this is the class for you.
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.#ctor(System.IO.Stream)">
+            <summary>Build a PgpSecretKeyRingBundle from the passed in input stream.</summary>
+            <param name="inputStream">Input stream containing data.</param>
+            <exception cref="T:System.IO.IOException">If a problem parsing the stream occurs.</exception>
+            <exception cref="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException">If an object is encountered which isn't a PgpSecretKeyRing.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.GetKeyRings">
+            <summary>Allow enumeration of the secret key rings making up this collection.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.GetKeyRings(System.String)">
+            <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+            <param name="userId">The user ID to be matched.</param>
+            <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.GetKeyRings(System.String,System.Boolean)">
+            <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+            <param name="userId">The user ID to be matched.</param>
+            <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+            <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.GetKeyRings(System.String,System.Boolean,System.Boolean)">
+            <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+            <param name="userId">The user ID to be matched.</param>
+            <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+            <param name="ignoreCase">If true, case is ignored in user ID comparisons.</param>
+            <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.GetSecretKey(System.Int64)">
+            <summary>Return the PGP secret key associated with the given key id.</summary>
+            <param name="keyId">The ID of the secret key to return.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.GetSecretKeyRing(System.Int64)">
+            <summary>Return the secret key ring which contains the key referred to by keyId</summary>
+            <param name="keyId">The ID of the secret key</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.Contains(System.Int64)">
+            <summary>
+            Return true if a key matching the passed in key ID is present, false otherwise.
+            </summary>
+            <param name="keyID">key ID to look for.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.AddSecretKeyRing(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle,Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing)">
+            <summary>
+            Return a new bundle containing the contents of the passed in bundle and
+            the passed in secret key ring.
+            </summary>
+            <param name="bundle">The <c>PgpSecretKeyRingBundle</c> the key ring is to be added to.</param>
+            <param name="secretKeyRing">The key ring to be added.</param>
+            <returns>A new <c>PgpSecretKeyRingBundle</c> merging the current one with the passed in key ring.</returns>
+            <exception cref="T:System.ArgumentException">If the keyId for the passed in key ring is already present.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.RemoveSecretKeyRing(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle,Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing)">
+            <summary>
+            Return a new bundle containing the contents of the passed in bundle with
+            the passed in secret key ring removed.
+            </summary>
+            <param name="bundle">The <c>PgpSecretKeyRingBundle</c> the key ring is to be removed from.</param>
+            <param name="secretKeyRing">The key ring to be removed.</param>
+            <returns>A new <c>PgpSecretKeyRingBundle</c> not containing the passed in key ring.</returns>
+            <exception cref="T:System.ArgumentException">If the keyId for the passed in key ring is not present.</exception>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.Count">
+            <summary>Return the number of rings in this collection.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature">
+            <remarks>A PGP signature object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.VerifyCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>
+            Verify the signature as certifying the passed in public key as associated
+            with the passed in user attributes.
+            </summary>
+            <param name="userAttributes">User attributes the key was stored under.</param>
+            <param name="key">The key to be verified.</param>
+            <returns>True, if the signature matches, false otherwise.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.VerifyCertification(System.String,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>
+            Verify the signature as certifying the passed in public key as associated
+            with the passed in ID.
+            </summary>
+            <param name="id">ID the key was stored under.</param>
+            <param name="key">The key to be verified.</param>
+            <returns>True, if the signature matches, false otherwise.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.VerifyCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Verify a certification for the passed in key against the passed in master key.</summary>
+            <param name="masterKey">The key we are verifying against.</param>
+            <param name="pubKey">The key we are verifying.</param>
+            <returns>True, if the certification is valid, false otherwise.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.VerifyCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Verify a key certification, such as revocation, for the passed in key.</summary>
+            <param name="pubKey">The key we are checking.</param>
+            <returns>True, if the certification is valid, false otherwise.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.Version">
+            <summary>The OpenPGP version number for this signature.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.KeyAlgorithm">
+            <summary>The key algorithm associated with this signature.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.HashAlgorithm">
+            <summary>The hash algorithm associated with this signature.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.KeyId">
+            <summary>The ID of the key that created the signature.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.CreationTime">
+            <summary>The creation time of this signature.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.HasSubpackets">
+            <summary>
+            Return true if the signature has either hashed or unhashed subpackets.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator">
+            <remarks>Generator for PGP signatures.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.#ctor(Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,Org.BouncyCastle.Bcpg.HashAlgorithmTag)">
+            <summary>Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.InitSign(System.Int32,Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey)">
+            <summary>Initialise the generator for signing.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.InitSign(System.Int32,Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey,Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Initialise the generator for signing.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.GenerateOnePassVersion(System.Boolean)">
+            <summary>Return the one pass header associated with the current signature.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.Generate">
+            <summary>Return a signature object containing the current signature state.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.GenerateCertification(System.String,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Generate a certification for the passed in ID and key.</summary>
+            <param name="id">The ID we are certifying against the public key.</param>
+            <param name="pubKey">The key we are certifying against the ID.</param>
+            <returns>The certification.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.GenerateCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Generate a certification for the passed in userAttributes.</summary>
+            <param name="userAttributes">The ID we are certifying against the public key.</param>
+            <param name="pubKey">The key we are certifying against the ID.</param>
+            <returns>The certification.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.GenerateCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Generate a certification for the passed in key against the passed in master key.</summary>
+            <param name="masterKey">The key we are certifying against.</param>
+            <param name="pubKey">The key we are certifying.</param>
+            <returns>The certification.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.GenerateCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Generate a certification, such as a revocation, for the passed in key.</summary>
+            <param name="pubKey">The key we are certifying.</param>
+            <returns>The certification.</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureList">
+            <remarks>A list of PGP signatures - normally in the signature block after literal data.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator">
+            <remarks>Generator for signature subpackets.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetTrust(System.Boolean,System.Int32,System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetKeyExpirationTime(System.Boolean,System.Int64)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetSignatureExpirationTime(System.Boolean,System.Int64)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetSignatureCreationTime(System.Boolean,System.DateTime)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetRevocationReason(System.Boolean,Org.BouncyCastle.Bcpg.RevocationReasonTag,System.String)">
+            <summary>
+            Sets revocation reason sub packet
+            </summary>	    
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetRevocationKey(System.Boolean,Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,System.Byte[])">
+            <summary>
+            Sets revocation key sub packet
+            </summary>	
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetIssuerKeyID(System.Boolean,System.Int64)">
+            <summary>
+            Sets issuer key sub packet
+            </summary>	
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector">
+            <remarks>Container for a list of signature subpackets.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector.HasSubpacket(Org.BouncyCastle.Bcpg.SignatureSubpacketTag)">
+             Return true if a particular subpacket type exists.
+            
+             @param type type to look for.
+             @return true if present, false otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector.GetSubpackets(Org.BouncyCastle.Bcpg.SignatureSubpacketTag)">
+            Return all signature subpackets of the passed in type.
+            @param type subpacket type code
+            @return an array of zero or more matching subpackets.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector.GetSignatureExpirationTime">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector.GetKeyExpirationTime">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector.Count">
+            <summary>Return the number of packets this vector contains.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector">
+            <remarks>Container for a list of user attribute subpackets.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpUtilities">
+            <remarks>Basic utility class.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpUtilities.GetDecoderStream(System.IO.Stream)">
+            <summary>
+            Return either an ArmoredInputStream or a BcpgInputStream based on whether
+            the initial characters of the stream are binary PGP encodings or not.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpV3SignatureGenerator">
+            <remarks>Generator for old style PGP V3 Signatures.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpV3SignatureGenerator.#ctor(Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,Org.BouncyCastle.Bcpg.HashAlgorithmTag)">
+            <summary>Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpV3SignatureGenerator.InitSign(System.Int32,Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey)">
+            <summary>Initialise the generator for signing.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpV3SignatureGenerator.InitSign(System.Int32,Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey,Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Initialise the generator for signing.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpV3SignatureGenerator.GenerateOnePassVersion(System.Boolean)">
+            <summary>Return the one pass header associated with the current signature.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpV3SignatureGenerator.Generate">
+            <summary>Return a V3 signature object containing the current signature state.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.OpenSsl.MiscPemGenerator">
+            PEM generator for the original set of PEM objects used in Open SSL.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.IO.Pem.PemObjectGenerator.Generate">
+            <returns>
+            A <see cref="T:Org.BouncyCastle.Utilities.IO.Pem.PemObject"/>
+            </returns>
+            <exception cref="T:Org.BouncyCastle.Utilities.IO.Pem.PemGenerationException"></exception>
+        </member>
+        <member name="T:Org.BouncyCastle.OpenSsl.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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.IO.Pem.PemReader.ReadPemObject">
+            <returns>
+            A <see cref="T:Org.BouncyCastle.Utilities.IO.Pem.PemObject"/>
+            </returns>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.#ctor(System.IO.TextReader)">
+             Create a new PemReader
+            
+             @param reader the Reader
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.#ctor(System.IO.TextReader,Org.BouncyCastle.OpenSsl.IPasswordFinder)">
+             Create a new PemReader with a password finder
+            
+             @param reader the Reader
+             @param pFinder the password finder
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.ReadCertificate(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+             Reads in a X509Certificate.
+            
+             @return the X509Certificate
+             @throws IOException if an I/O error occured
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.ReadCrl(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+             Reads in a X509CRL.
+            
+             @return the X509Certificate
+             @throws IOException if an I/O error occured
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.ReadCertificateRequest(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+             Reads in a PKCS10 certification request.
+            
+             @return the certificate request.
+             @throws IOException if an I/O error occured
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.ReadAttributeCertificate(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+             Reads in a X509 Attribute Certificate.
+            
+             @return the X509 Attribute Certificate
+             @throws IOException if an I/O error occured
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.ReadPkcs7(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.ReadPrivateKey(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+            Read a Key Pair
+        </member>
+        <member name="T:Org.BouncyCastle.OpenSsl.PemWriter">
+            <remarks>General purpose writer for OpenSSL PEM objects.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.IO.Pem.PemWriter">
+            A generic PEM writer, based on RFC 1421
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.IO.Pem.PemWriter.#ctor(System.IO.TextWriter)">
+             Base constructor.
+            
+             @param out output stream to use.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.IO.Pem.PemWriter.GetOutputSize(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemWriter.#ctor(System.IO.TextWriter)">
+            <param name="writer">The TextWriter object to write the output to.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.Pkcs8Generator.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+             Constructor for an unencrypted private key PEM object.
+            
+             @param key private key to be encoded.
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.Pkcs8Generator.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.String)">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest">
+             <remarks>
+             A class for verifying and creating Pkcs10 Certification requests.
+             </remarks>
+             <code>
+             CertificationRequest ::= Sequence {
+               certificationRequestInfo  CertificationRequestInfo,
+               signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+               signature                 BIT STRING
+             }
+            
+             CertificationRequestInfo ::= Sequence {
+               version             Integer { v1(0) } (v1,...),
+               subject             Name,
+               subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+               attributes          [0] Attributes{{ CRIAttributes }}
+              }
+            
+              Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }}
+            
+              Attr { ATTRIBUTE:IOSet } ::= Sequence {
+                type    ATTRIBUTE.&amp;id({IOSet}),
+                values  Set SIZE(1..MAX) OF ATTRIBUTE.&amp;Type({IOSet}{\@type})
+              }
+             </code>
+             see <a href="http://www.rsasecurity.com/rsalabs/node.asp?id=2132"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest.#ctor(System.String,Org.BouncyCastle.Asn1.X509.X509Name,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Asn1.Asn1Set,Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+             <summary>
+             Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+             </summary>
+            <param name="signatureAlgorithm">Name of Sig Alg.</param>
+             <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param>
+             <param name="publicKey">Public Key to be included in cert reqest.</param>
+             <param name="attributes">ASN1Set of Attributes.</param>
+             <param name="signingKey">Matching Private key for nominated (above) public key to be used to sign the request.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest.GetPublicKey">
+            <summary>
+            Get the public key.
+            </summary>
+            <returns>The public key.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest.Verify">
+            <summary>
+            Verify Pkcs10 Cert Request is valid.
+            </summary>
+            <returns>true = valid.</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequestDelaySigned">
+             <remarks>
+             A class for creating and verifying Pkcs10 Certification requests (this is an extension on <see cref="T:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest"/>).
+             The requests are made using delay signing. This is useful for situations where
+             the private key is in another environment and not directly accessible (e.g. HSM)
+             So the first step creates the request, then the signing is done outside this
+             object and the signature is then used to complete the request.
+             </remarks>
+             <code>
+             CertificationRequest ::= Sequence {
+               certificationRequestInfo  CertificationRequestInfo,
+               signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+               signature                 BIT STRING
+             }
+            
+             CertificationRequestInfo ::= Sequence {
+               version             Integer { v1(0) } (v1,...),
+               subject             Name,
+               subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+               attributes          [0] Attributes{{ CRIAttributes }}
+              }
+            
+              Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }}
+            
+              Attr { ATTRIBUTE:IOSet } ::= Sequence {
+                type    ATTRIBUTE.&amp;id({IOSet}),
+                values  Set SIZE(1..MAX) OF ATTRIBUTE.&amp;Type({IOSet}{\@type})
+              }
+             </code>
+             see <a href="http://www.rsasecurity.com/rsalabs/node.asp?id=2132"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequestDelaySigned.#ctor(System.String,Org.BouncyCastle.Asn1.X509.X509Name,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Asn1.Asn1Set)">
+            <summary>
+            Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+            </summary>
+            <param name="signatureAlgorithm">Name of Sig Alg.</param>
+            <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param>
+            <param name="publicKey">Public Key to be included in cert reqest.</param>
+            <param name="attributes">ASN1Set of Attributes.</param>
+            <remarks>
+            After the object is constructed use the <see cref="M:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequestDelaySigned.GetDataToSign"/> and finally the
+            SignRequest methods to finalize the request.
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs12Store.GetCertificate(System.String)">
+            simply return the cert entry for the private key
+        </member>
+        <member name="T:Org.BouncyCastle.Pkcs.Pkcs12Utilities">
+            Utility class for reencoding PKCS#12 files to definite length.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs12Utilities.ConvertToDefiniteLength(System.Byte[])">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs12Utilities.ConvertToDefiniteLength(System.Byte[],System.Char[])">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.CertStatus.RevocationDate">
+            <summary>
+            Returns the revocationDate.
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.CertStatus.Status">
+            <summary>
+            Returns the certStatus.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixAttrCertChecker.GetSupportedExtensions">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixAttrCertChecker.Check(Org.BouncyCastle.X509.IX509AttributeCertificate,Org.BouncyCastle.Pkix.PkixCertPath,Org.BouncyCastle.Pkix.PkixCertPath,System.Collections.ICollection)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixAttrCertChecker.Clone">
+            Returns a clone of this object.
+            
+            @return a copy of this <code>PkixAttrCertChecker</code>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixAttrCertPathBuilder.Build(Org.BouncyCastle.Pkix.PkixBuilderParameters)">
+             Build and validate a CertPath using the given parameter.
+            
+             @param params PKIXBuilderParameters object containing all information to
+                        build the CertPath
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixAttrCertPathValidator">
+            CertPathValidatorSpi implementation for X.509 Attribute Certificates la RFC 3281.
+            
+            @see org.bouncycastle.x509.ExtendedPkixParameters
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixAttrCertPathValidator.Validate(Org.BouncyCastle.Pkix.PkixCertPath,Org.BouncyCastle.Pkix.PkixParameters)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixBuilderParameters">
+            <summary>
+            Summary description for PkixBuilderParameters.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixParameters">
+            <summary>
+            Summary description for PkixParameters.
+            </summary>
+        </member>
+        <member name="F:Org.BouncyCastle.Pkix.PkixParameters.PkixValidityModel">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Pkix.PkixParameters.ChainValidityModel">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.#ctor(Org.BouncyCastle.Utilities.Collections.ISet)">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetTargetCertConstraints">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetTargetCertConstraints(Org.BouncyCastle.X509.Store.IX509Selector)">
+             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()
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetInitialPolicies">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetInitialPolicies(Org.BouncyCastle.Utilities.Collections.ISet)">
+             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()
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetCertPathCheckers(System.Collections.IList)">
+             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()
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetCertPathCheckers">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.AddCertPathChecker(Org.BouncyCastle.Pkix.PkixCertPathChecker)">
+             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).
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetParams(Org.BouncyCastle.Pkix.PkixParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetStores(System.Collections.IList)">
+             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}.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.AddStore(Org.BouncyCastle.X509.Store.IX509Store)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.AddAdditionalStore(Org.BouncyCastle.X509.Store.IX509Store)">
+             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()
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetAdditionalStores">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetStores">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetAdditionalLocationsEnabled(System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetTargetConstraints">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetTargetConstraints(Org.BouncyCastle.X509.Store.IX509Selector)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetTrustedACIssuers">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetTrustedACIssuers(Org.BouncyCastle.Utilities.Collections.ISet)">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetNecessaryACAttributes">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetNecessaryACAttributes(Org.BouncyCastle.Utilities.Collections.ISet)">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetProhibitedACAttributes">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetProhibitedACAttributes(Org.BouncyCastle.Utilities.Collections.ISet)">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetAttrCertCheckers">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetAttrCertCheckers(Org.BouncyCastle.Utilities.Collections.ISet)">
+             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>.
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixParameters.IsUseDeltasEnabled">
+            Whether delta CRLs should be used for checking the revocation status.
+            Defaults to <code>false</code>.
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixParameters.ValidityModel">
+            The validity model.
+            @see #CHAIN_VALIDITY_MODEL
+            @see #PKIX_VALIDITY_MODEL
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixParameters.IsAdditionalLocationsEnabled">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixBuilderParameters.GetInstance(Org.BouncyCastle.Pkix.PkixParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixBuilderParameters.GetExcludedCerts">
+            <summary>
+            Excluded certificates are not used for building a certification path.
+            </summary>
+            <returns>the excluded certificates.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixBuilderParameters.SetExcludedCerts(Org.BouncyCastle.Utilities.Collections.ISet)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixBuilderParameters.SetParams(Org.BouncyCastle.Pkix.PkixParameters)">
+            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)
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixBuilderParameters.Clone">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPath">
+             An immutable sequence of certificates (a certification path).<br />
+             <br />
+             This is an abstract class that defines the methods common to all CertPaths.
+             Subclasses can handle different kinds of certificates (X.509, PGP, etc.).<br />
+             <br />
+             All CertPath objects have a type, a list of Certificates, and one or more
+             supported encodings. Because the CertPath class is immutable, a CertPath
+             cannot change in any externally visible way after being constructed. This
+             stipulation applies to all public fields and methods of this class and any
+             added or overridden by subclasses.<br />
+             <br />
+             The type is a string that identifies the type of Certificates in the
+             certification path. For each certificate cert in a certification path
+             certPath, cert.getType().equals(certPath.getType()) must be true.<br />
+             <br />
+             The list of Certificates is an ordered List of zero or more Certificates.
+             This List and all of the Certificates contained in it must be immutable.<br />
+             <br />
+             Each CertPath object must support one or more encodings so that the object
+             can be translated into a byte array for storage or transmission to other
+             parties. Preferably, these encodings should be well-documented standards
+             (such as PKCS#7). One of the encodings supported by a CertPath is considered
+             the default encoding. This encoding is used if no encoding is explicitly
+             requested (for the {@link #getEncoded()} method, for instance).<br />
+             <br />
+             All CertPath objects are also Serializable. CertPath objects are resolved
+             into an alternate {@link CertPathRep} object during serialization. This
+             allows a CertPath object to be serialized into an equivalent representation
+             regardless of its underlying implementation.<br />
+             <br />
+             CertPath objects can be created with a CertificateFactory or they can be
+             returned by other classes, such as a CertPathBuilder.<br />
+             <br />
+             By convention, X.509 CertPaths (consisting of X509Certificates), are ordered
+             starting with the target certificate and ending with a certificate issued by
+             the trust anchor. That is, the issuer of one certificate is the subject of
+             the following one. The certificate representing the
+             {@link TrustAnchor TrustAnchor} should not be included in the certification
+             path. Unvalidated X.509 CertPaths may not follow these conventions. PKIX
+             CertPathValidators will detect any departure from these conventions that
+             cause the certification path to be invalid and throw a
+             CertPathValidatorException.<br />
+             <br />
+             <strong>Concurrent Access</strong><br />
+             <br />
+             All CertPath objects must be thread-safe. That is, multiple threads may
+             concurrently invoke the methods defined in this class on a single CertPath
+             object (or more than one) with no ill effects. This is also true for the List
+             returned by CertPath.getCertificates.<br />
+             <br />
+             Requiring CertPath objects to be immutable and thread-safe allows them to be
+             passed around to various pieces of code without worrying about coordinating
+             access. Providing this thread-safety is generally not difficult, since the
+             CertPath and List objects in question are immutable.
+            
+             @see CertificateFactory
+             @see CertPathBuilder
+            <summary>
+            CertPath implementation for X.509 certificates.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.SortCerts(System.Collections.IList)">
+            @param certs
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.#ctor(System.Collections.ICollection)">
+             Creates a CertPath of the specified type.
+             This constructor is protected because most users should use
+             a CertificateFactory to create CertPaths.
+             @param type the standard name of the type of Certificatesin this path
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.#ctor(System.IO.Stream,System.String)">
+             Creates a CertPath of the specified type.
+             This constructor is protected because most users should use
+             a CertificateFactory to create CertPaths.
+            
+             @param type the standard name of the type of Certificatesin this path
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.Equals(System.Object)">
+             Compares this certification path for equality with the specified object.
+             Two CertPaths are equal if and only if their types are equal and their
+             certificate Lists (and by implication the Certificates in those Lists)
+             are equal. A CertPath is never equal to an object that is not a CertPath.<br />
+             <br />
+             This algorithm is implemented by this method. If it is overridden, the
+             behavior specified here must be maintained.
+            
+             @param other
+                        the object to test for equality with this certification path
+            
+             @return true if the specified object is equal to this certification path,
+                     false otherwise
+            
+             @see Object#hashCode() Object.hashCode()
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.GetEncoded">
+             Returns the encoded form of this certification path, using
+             the default encoding.
+            
+             @return the encoded bytes
+             @exception CertificateEncodingException if an encoding error occurs
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.GetEncoded(System.String)">
+             Returns the encoded form of this certification path, using
+             the specified encoding.
+            
+             @param encoding the name of the encoding to use
+             @return the encoded bytes
+             @exception CertificateEncodingException if an encoding error
+             occurs or the encoding requested is not supported
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.ToAsn1Object(Org.BouncyCastle.X509.X509Certificate)">
+             Return a DERObject containing the encoded certificate.
+            
+             @param cert the X509Certificate object to be encoded
+            
+             @return the DERObject
+            
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixCertPath.Encodings">
+             Returns an iteration of the encodings supported by this
+             certification path, with the default encoding
+             first. Attempts to modify the returned Iterator via its
+             remove method result in an UnsupportedOperationException.
+            
+             @return an Iterator over the names of the supported encodings (as Strings)
+            
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixCertPath.Certificates">
+            <summary>
+            Returns the list of certificates in this certification
+            path.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathBuilder">
+             Implements the PKIX CertPathBuilding algorithm for BouncyCastle.
+            
+             @see CertPathBuilderSpi
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathBuilder.Build(Org.BouncyCastle.Pkix.PkixBuilderParameters)">
+             Build and validate a CertPath using the given parameter.
+            
+             @param params PKIXBuilderParameters object containing all information to
+                        build the CertPath
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathBuilderException">
+            <summary>
+            Summary description for PkixCertPathBuilderException.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathBuilderResult">
+            <summary>
+            Summary description for PkixCertPathBuilderResult.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathValidatorResult">
+            <summary>
+            Summary description for PkixCertPathValidatorResult.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathChecker.Init(System.Boolean)">
+                     * 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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathChecker.IsForwardCheckingSupported">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathChecker.GetSupportedExtensions">
+                     * 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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathChecker.Check(Org.BouncyCastle.X509.X509Certificate,System.Collections.ICollection)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathChecker.Clone">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathValidator">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathValidatorException">
+             An exception indicating one of a variety of problems encountered when 
+             validating a certification path. <br />
+             <br />
+             A <code>CertPathValidatorException</code> provides support for wrapping
+             exceptions. The {@link #getCause getCause} method returns the throwable, 
+             if any, that caused this exception to be thrown. <br />
+             <br />
+             A <code>CertPathValidatorException</code> may also include the 
+             certification path that was being validated when the exception was thrown 
+             and the index of the certificate in the certification path that caused the 
+             exception to be thrown. Use the {@link #getCertPath getCertPath} and
+             {@link #getIndex getIndex} methods to retrieve this information.<br />
+             <br />
+             <b>Concurrent Access</b><br />
+             <br />
+             Unless otherwise specified, the methods defined in this class are not
+             thread-safe. Multiple threads that need to access a single
+             object concurrently should synchronize amongst themselves and
+             provide the necessary locking. Multiple threads each manipulating
+             separate objects need not synchronize.
+            
+             @see CertPathValidator
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorException.#ctor(System.String)">
+            <summary>
+            Creates a <code>PkixCertPathValidatorException</code> with the given detail
+            message. A detail message is a <code>String</code> that describes this
+            particular exception. 
+            </summary>
+            <param name="message">the detail message</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorException.#ctor(System.String,System.Exception)">
+            <summary>
+            Creates a <code>PkixCertPathValidatorException</code> with the specified
+            detail message and cause.
+            </summary>
+            <param name="message">the detail message</param>
+            <param name="cause">the cause (which is saved for later retrieval by the
+            {@link #getCause getCause()} method). (A <code>null</code>
+            value is permitted, and indicates that the cause is
+            nonexistent or unknown.)</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorException.#ctor(System.String,System.Exception,Org.BouncyCastle.Pkix.PkixCertPath,System.Int32)">
+            <summary>
+            Creates a <code>PkixCertPathValidatorException</code> with the specified
+            detail message, cause, certification path, and index.
+            </summary>
+            <param name="message">the detail message (or <code>null</code> if none)</param>
+            <param name="cause">the cause (or <code>null</code> if none)</param>
+            <param name="certPath">the certification path that was in the process of being
+            validated when the error was encountered</param>
+            <param name="index">the index of the certificate in the certification path that</param>																																																																																   * 
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixCertPathValidatorException.Message">
+            <summary>
+            Returns the detail message for this <code>CertPathValidatorException</code>.
+            </summary>
+            <returns>the detail message, or <code>null</code> if neither the message nor cause were specified</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixCertPathValidatorException.CertPath">
+            Returns the certification path that was being validated when the
+            exception was thrown.
+            
+            @return the <code>CertPath</code> that was being validated when the
+                    exception was thrown (or <code>null</code> if not specified)
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixCertPathValidatorException.Index">
+            Returns the index of the certificate in the certification path that
+            caused the exception to be thrown. Note that the list of certificates in
+            a <code>CertPath</code> is zero based. If no index has been set, -1 is
+            returned.
+            
+            @return the index that has been set, or -1 if none has been set
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities">
+            <summary>
+            Summary description for PkixCertPathValidatorUtilities.
+            </summary>
+        </member>
+        <member name="F:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.KEY_CERT_SIGN">
+            <summary>
+            key usage bits
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.FindTrustAnchor(Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Utilities.Collections.ISet)">
+            <summary>
+            Search the given Set of TrustAnchor's for one that is the
+            issuer of the given X509 certificate.
+            </summary>
+            <param name="cert">the X509 certificate</param>
+            <param name="trustAnchors">a Set of TrustAnchor's</param>
+            <returns>the <code>TrustAnchor</code> object if found or
+            <code>null</code> if not.
+            </returns>
+            @exception
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.GetIssuerPrincipal(System.Object)">
+            <summary>
+            Returns the issuer of an attribute certificate or certificate.
+            </summary>
+            <param name="cert">The attribute certificate or certificate.</param>
+            <returns>The issuer as <code>X500Principal</code>.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.GetNextWorkingKey(System.Collections.IList,System.Int32)">
+             Return the next working key inheriting DSA parameters if necessary.
+             <p>
+             This methods inherits DSA parameters from the indexed certificate or
+             previous certificates in the certificate chain to the returned
+             <code>PublicKey</code>. The list is searched upwards, meaning the end
+             certificate is at position 0 and previous certificates are following.
+             </p>
+             <p>
+             If the indexed certificate does not contain a DSA key this method simply
+             returns the public key. If the DSA key already contains DSA parameters
+             the key is also only returned.
+             </p>
+            
+             @param certs The certification path.
+             @param index The index of the certificate which contains the public key
+                        which should be extended with DSA parameters.
+             @return The public key of the certificate in list position
+                     <code>index</code> extended with DSA parameters if applicable.
+             @throws Exception if DSA parameters cannot be inherited.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.FindCertificates(Org.BouncyCastle.X509.Store.X509CertStoreSelector,System.Collections.IList)">
+            <summary>
+            Return a Collection of all certificates or attribute certificates found
+            in the X509Store's that are matching the certSelect criteriums.
+            </summary>
+            <param name="certSelect">a {@link Selector} object that will be used to select
+            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="T:Org.BouncyCastle.X509.X509Certificate"/> or
+            org.bouncycastle.x509.X509AttributeCertificate objects.
+            May be empty but never <code>null</code>.</returns>
+            <exception cref="T:System.Exception"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.GetCrlIssuersFromDistributionPoint(Org.BouncyCastle.Asn1.X509.DistributionPoint,System.Collections.ICollection,Org.BouncyCastle.X509.Store.X509CrlStoreSelector,Org.BouncyCastle.Pkix.PkixParameters)">
+             Add the CRL issuers from the cRLIssuer field of the distribution point or
+             from the certificate if not given to the issuer criterion of the
+             <code>selector</code>.
+             <p>
+             The <code>issuerPrincipals</code> are a collection with a single
+             <code>X500Principal</code> for <code>X509Certificate</code>s. For
+             {@link X509AttributeCertificate}s the issuer may contain more than one
+             <code>X500Principal</code>.
+             </p>
+            
+             @param dp The distribution point.
+             @param issuerPrincipals The issuers of the certificate or attribute
+                        certificate which contains the distribution point.
+             @param selector The CRL selector.
+             @param pkixParams The PKIX parameters containing the cert stores.
+             @throws Exception if an exception occurs while processing.
+             @throws ClassCastException if <code>issuerPrincipals</code> does not
+             contain only <code>X500Principal</code>s.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.GetCompleteCrls(Org.BouncyCastle.Asn1.X509.DistributionPoint,System.Object,System.DateTime,Org.BouncyCastle.Pkix.PkixParameters)">
+             Fetches complete CRLs according to RFC 3280.
+            
+             @param dp The distribution point for which the complete CRL
+             @param cert The <code>X509Certificate</code> or
+                        {@link org.bouncycastle.x509.X509AttributeCertificate} for
+                        which the CRL should be searched.
+             @param currentDate The date for which the delta CRLs must be valid.
+             @param paramsPKIX The extended PKIX parameters.
+             @return A <code>Set</code> of <code>X509CRL</code>s with complete
+                     CRLs.
+             @throws Exception if an exception occurs while picking the CRLs
+                         or no CRLs are found.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.GetDeltaCrls(System.DateTime,Org.BouncyCastle.Pkix.PkixParameters,Org.BouncyCastle.X509.X509Crl)">
+             Fetches delta CRLs according to RFC 3280 section 5.2.4.
+            
+             @param currentDate The date for which the delta CRLs must be valid.
+             @param paramsPKIX The extended PKIX parameters.
+             @param completeCRL The complete CRL the delta CRL is for.
+             @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
+             @throws Exception if an exception occurs while picking the delta
+                         CRLs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.FindIssuerCerts(Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Pkix.PkixBuilderParameters)">
+             Find the issuer certificates of a given certificate.
+            
+             @param cert
+                        The certificate for which an issuer should be found.
+             @param pkixParams
+             @return A <code>Collection</code> object containing the issuer
+                     <code>X509Certificate</code>s. Never <code>null</code>.
+            
+             @exception Exception
+                            if an error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.GetExtensionValue(Org.BouncyCastle.X509.IX509Extension,Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            <summary>
+            Extract the value of the given extension, if it exists.
+            </summary>
+            <param name="ext">The extension object.</param>
+            <param name="oid">The object identifier to obtain.</param>
+            <returns>Asn1Object</returns>
+            <exception cref="T:System.Exception">if the extension cannot be read.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCrlUtilities.FindCrls(Org.BouncyCastle.X509.Store.X509CrlStoreSelector,System.Collections.IList)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.IntersectIP(Org.BouncyCastle.Utilities.Collections.ISet,Org.BouncyCastle.Utilities.Collections.ISet)">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.UnionIP(Org.BouncyCastle.Utilities.Collections.ISet,System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.UnionIPRange(System.Byte[],System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.IntersectIPRange(System.Byte[],System.Byte[])">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.IpWithSubnetMask(System.Byte[],System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.ExtractIPsAndSubnetMasks(System.Byte[],System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.MinMaxIPs(System.Byte[],System.Byte[],System.Byte[],System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.CheckPermittedIP(Org.BouncyCastle.Utilities.Collections.ISet,System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.checkExcludedIP(Org.BouncyCastle.Utilities.Collections.ISet,System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.IsIPConstrained(System.Byte[],System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.unionEmail(System.String,System.String,Org.BouncyCastle.Utilities.Collections.ISet)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.intersectEmail(System.String,System.String,Org.BouncyCastle.Utilities.Collections.ISet)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.checkPermitted(Org.BouncyCastle.Asn1.X509.GeneralName)">
+             Checks if the given GeneralName is in the permitted ISet.
+            
+             @param name The GeneralName
+             @throws PkixNameConstraintValidatorException
+                      If the <code>name</code>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.checkExcluded(Org.BouncyCastle.Asn1.X509.GeneralName)">
+             Check if the given GeneralName is contained in the excluded ISet.
+            
+             @param name The GeneralName.
+             @throws PkixNameConstraintValidatorException
+                      If the <code>name</code> is
+                      excluded.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.IntersectPermittedSubtree(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Updates the permitted ISet of these name constraints with the intersection
+             with the given subtree.
+            
+             @param permitted The permitted subtrees
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.AddExcludedSubtree(Org.BouncyCastle.Asn1.X509.GeneralSubtree)">
+             Adds a subtree to the excluded ISet of these name constraints.
+            
+             @param subtree A subtree with an excluded GeneralName.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.Max(System.Byte[],System.Byte[])">
+             Returns the maximum IP address.
+            
+             @param ip1 The first IP address.
+             @param ip2 The second IP address.
+             @return The maximum IP address.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.Min(System.Byte[],System.Byte[])">
+             Returns the minimum IP address.
+            
+             @param ip1 The first IP address.
+             @param ip2 The second IP address.
+             @return The minimum IP address.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.CompareTo(System.Byte[],System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.Or(System.Byte[],System.Byte[])">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.StringifyIP(System.Byte[])">
+             Stringifies an IPv4 or v6 address with subnet mask.
+            
+             @param ip The IP with subnet mask.
+             @return The stringified IP address.
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixPolicyNode">
+            <summary>
+            Summary description for PkixPolicyNode.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixPolicyNode.#ctor(System.Collections.IList,System.Int32,Org.BouncyCastle.Utilities.Collections.ISet,Org.BouncyCastle.Pkix.PkixPolicyNode,Org.BouncyCastle.Utilities.Collections.ISet,System.String,System.Boolean)">
+            Constructors
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.ReasonsMask">
+            <summary>
+            This class helps to handle CRL revocation reasons mask. Each CRL handles a
+            certain set of revocation reasons.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.ReasonsMask.#ctor(System.Int32)">
+            <summary>
+            Constructs are reason mask with the reasons.
+            </summary>
+            <param name="reasons">The reasons.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.ReasonsMask.#ctor">
+            <summary>
+            A reason mask with no reason.
+            </summary>
+        </member>
+        <member name="F:Org.BouncyCastle.Pkix.ReasonsMask.AllReasons">
+            <summary>
+            A mask with all revocation reasons.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.ReasonsMask.AddReasons(Org.BouncyCastle.Pkix.ReasonsMask)">
+             Adds all reasons from the reasons mask to this mask.
+            
+             @param mask The reasons mask to add.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.ReasonsMask.Intersect(Org.BouncyCastle.Pkix.ReasonsMask)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.ReasonsMask.HasNewReasons(Org.BouncyCastle.Pkix.ReasonsMask)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.ReasonsMask.IsAllReasons">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.ReasonsMask.Reasons">
+            <summary>
+            Returns the reasons in this mask.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3280CertPathUtilities.ProcessCrlB2(Org.BouncyCastle.Asn1.X509.DistributionPoint,System.Object,Org.BouncyCastle.X509.X509Crl)">
+             If the complete CRL includes an issuing distribution point (IDP) CRL
+             extension check the following:
+             <p>
+             (i) If the distribution point name is present in the IDP CRL extension
+             and the distribution field is present in the DP, then verify that one of
+             the names in the IDP matches one of the names in the DP. If the
+             distribution point name is present in the IDP CRL extension and the
+             distribution field is omitted from the DP, then verify that one of the
+             names in the IDP matches one of the names in the cRLIssuer field of the
+             DP.
+             </p>
+             <p>
+             (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL
+             extension, verify that the certificate does not include the basic
+             constraints extension with the cA boolean asserted.
+             </p>
+             <p>
+             (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL
+             extension, verify that the certificate includes the basic constraints
+             extension with the cA boolean asserted.
+             </p>
+             <p>
+             (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted.
+             </p>
+            
+             @param dp   The distribution point.
+             @param cert The certificate.
+             @param crl  The CRL.
+             @throws AnnotatedException if one of the conditions is not met or an error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3280CertPathUtilities.ProcessCrlB1(Org.BouncyCastle.Asn1.X509.DistributionPoint,System.Object,Org.BouncyCastle.X509.X509Crl)">
+             If the DP includes cRLIssuer, then verify that the issuer field in the
+             complete CRL matches cRLIssuer in the DP and that the complete CRL
+             contains an
+                  g distribution point extension with the indirectCRL
+             boolean asserted. Otherwise, verify that the CRL issuer matches the
+             certificate issuer.
+            
+             @param dp   The distribution point.
+             @param cert The certificate ot attribute certificate.
+             @param crl  The CRL for <code>cert</code>.
+             @throws AnnotatedException if one of the above conditions does not apply or an error
+                                        occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3280CertPathUtilities.ProcessCrlF(Org.BouncyCastle.X509.X509Crl,System.Object,Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Pkix.PkixParameters,System.Collections.IList)">
+             Obtain and validate the certification path for the complete CRL issuer.
+             If a key usage extension is present in the CRL issuer's certificate,
+             verify that the cRLSign bit is set.
+            
+             @param crl                CRL which contains revocation information for the certificate
+                                       <code>cert</code>.
+             @param cert               The attribute certificate or certificate to check if it is
+                                       revoked.
+             @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+             @param defaultCRLSignKey  The public key of the issuer certificate
+                                       <code>defaultCRLSignCert</code>.
+             @param paramsPKIX         paramsPKIX PKIX parameters.
+             @param certPathCerts      The certificates on the certification path.
+             @return A <code>Set</code> with all keys of possible CRL issuer
+                     certificates.
+             @throws AnnotatedException if the CRL is not valid or the status cannot be checked or
+                                        some error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3280CertPathUtilities.CheckCrl(Org.BouncyCastle.Asn1.X509.DistributionPoint,Org.BouncyCastle.Pkix.PkixParameters,Org.BouncyCastle.X509.X509Certificate,System.DateTime,Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Pkix.CertStatus,Org.BouncyCastle.Pkix.ReasonsMask,System.Collections.IList)">
+             Checks a distribution point for revocation information for the
+             certificate <code>cert</code>.
+            
+             @param dp                 The distribution point to consider.
+             @param paramsPKIX         PKIX parameters.
+             @param cert               Certificate to check if it is revoked.
+             @param validDate          The date when the certificate revocation status should be
+                                       checked.
+             @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+             @param defaultCRLSignKey  The public key of the issuer certificate
+                                       <code>defaultCRLSignCert</code>.
+             @param certStatus         The current certificate revocation status.
+             @param reasonMask         The reasons mask which is already checked.
+             @param certPathCerts      The certificates of the certification path.
+             @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+                                        or some error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3280CertPathUtilities.CheckCrls(Org.BouncyCastle.Pkix.PkixParameters,Org.BouncyCastle.X509.X509Certificate,System.DateTime,Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Collections.IList)">
+             Checks a certificate if it is revoked.
+            
+             @param paramsPKIX       PKIX parameters.
+             @param cert             Certificate to check if it is revoked.
+             @param validDate        The date when the certificate revocation status should be
+                                     checked.
+             @param sign             The issuer certificate of the certificate <code>cert</code>.
+             @param workingPublicKey The public key of the issuer certificate <code>sign</code>.
+             @param certPathCerts    The certificates of the certification path.
+             @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+                                        or some error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3280CertPathUtilities.ProcessCrlC(Org.BouncyCastle.X509.X509Crl,Org.BouncyCastle.X509.X509Crl,Org.BouncyCastle.Pkix.PkixParameters)">
+             If use-deltas is set, verify the issuer and scope of the delta CRL.
+            
+             @param deltaCRL    The delta CRL.
+             @param completeCRL The complete CRL.
+             @param pkixParams  The PKIX paramaters.
+             @throws AnnotatedException if an exception occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3281CertPathUtilities.CheckCrls(Org.BouncyCastle.X509.IX509AttributeCertificate,Org.BouncyCastle.Pkix.PkixParameters,Org.BouncyCastle.X509.X509Certificate,System.DateTime,System.Collections.IList)">
+            Checks if an attribute certificate is revoked.
+            
+            @param attrCert Attribute certificate to check if it is revoked.
+            @param paramsPKIX PKIX parameters.
+            @param issuerCert The issuer certificate of the attribute certificate
+                       <code>attrCert</code>.
+            @param validDate The date when the certificate revocation status should
+                       be checked.
+            @param certPathCerts The certificates of the certification path to be
+                       checked.
+            
+            @throws CertPathValidatorException if the certificate is revoked or the
+                        status cannot be checked or some error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3281CertPathUtilities.ProcessAttrCert1(Org.BouncyCastle.X509.IX509AttributeCertificate,Org.BouncyCastle.Pkix.PkixParameters)">
+            Searches for a holder public key certificate and verifies its
+            certification path.
+            
+            @param attrCert the attribute certificate.
+            @param pkixParams The PKIX parameters.
+            @return The certificate path of the holder certificate.
+            @throws Exception if
+                        <ul>
+                        <li>no public key certificate can be found although holder
+                        information is given by an entity name or a base certificate
+                        ID</li>
+                        <li>support classes cannot be created</li>
+                        <li>no certification path for the public key certificate can
+                        be built</li>
+                        </ul>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3281CertPathUtilities.CheckCrl(Org.BouncyCastle.Asn1.X509.DistributionPoint,Org.BouncyCastle.X509.IX509AttributeCertificate,Org.BouncyCastle.Pkix.PkixParameters,System.DateTime,Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Pkix.CertStatus,Org.BouncyCastle.Pkix.ReasonsMask,System.Collections.IList)">
+            
+            Checks a distribution point for revocation information for the
+            certificate <code>attrCert</code>.
+            
+            @param dp The distribution point to consider.
+            @param attrCert The attribute certificate which should be checked.
+            @param paramsPKIX PKIX parameters.
+            @param validDate The date when the certificate revocation status should
+                       be checked.
+            @param issuerCert Certificate to check if it is revoked.
+            @param reasonMask The reasons mask which is already checked.
+            @param certPathCerts The certificates of the certification path to be
+                       checked.
+            @throws Exception if the certificate is revoked or the status
+                        cannot be checked or some error occurs.
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.TrustAnchor">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.TrustAnchor.#ctor(Org.BouncyCastle.X509.X509Certificate,System.Byte[])">
+             <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="T:System.ArgumentNullException">if the specified X509Certificate is null</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.TrustAnchor.#ctor(Org.BouncyCastle.Asn1.X509.X509Name,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[])">
+            <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="T:System.ArgumentNullException">
+            if <c>caPrincipal</c> or <c>pubKey</c> is null
+            </exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.TrustAnchor.#ctor(System.String,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[])">
+            <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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.TrustAnchor.setNameConstraints(System.Byte[])">
+            <summary>
+            Decode the name constraints and clone them if not null.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.TrustAnchor.ToString">
+            <summary>
+            Returns a formatted string describing the <code>TrustAnchor</code>.
+            </summary>
+            <returns>a formatted string describing the <code>TrustAnchor</code></returns>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.TrustAnchor.TrustedCert">
+            <summary>
+            Returns the most-trusted CA certificate.
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.TrustAnchor.CA">
+            <summary>
+            Returns the name of the most-trusted CA as an X509Name.
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.TrustAnchor.CAName">
+            <summary>
+            Returns the name of the most-trusted CA in RFC 2253 string format.
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.TrustAnchor.CAPublicKey">
+            <summary>
+            Returns the public key of the most-trusted CA.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Security.AgreementUtilities">
+            <remarks>
+             Utility class for creating IBasicAgreement objects from their names/Oids
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Security.CipherUtilities">
+            <remarks>
+             Cipher Utility class contains methods that can not be specifically grouped into other classes.
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Security.CipherUtilities.GetObjectIdentifier(System.String)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Security.DigestUtilities">
+            <remarks>
+             Utility class for creating IDigest objects from their names/Oids
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Security.DigestUtilities.GetObjectIdentifier(System.String)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Security.MacUtilities">
+            <remarks>
+             Utility class for creating HMac object from their names/Oids
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Security.PbeUtilities">
+             <summary>
+            
+             </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Security.PbeUtilities.GetObjectIdentifier(System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Security.SecureRandom.#ctor(Org.BouncyCastle.Crypto.Prng.IRandomGenerator)">
+            <summary>Use the specified instance of IRandomGenerator as random source.</summary>
+            <remarks>
+            This constructor performs no seeding of either the <c>IRandomGenerator</c> or the
+            constructed <c>SecureRandom</c>. It is the responsibility of the client to provide
+            proper seed material as necessary/appropriate for the given <c>IRandomGenerator</c>
+            implementation.
+            </remarks>
+            <param name="generator">The source to generate all random bytes from.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Security.SecurityUtilityException.#ctor">
+            base constructor.
+        </member>
+        <member name="M:Org.BouncyCastle.Security.SecurityUtilityException.#ctor(System.String)">
+             create a SecurityUtilityException with the given message.
+            
+             @param message the message to be carried with the exception.
+        </member>
+        <member name="T:Org.BouncyCastle.Security.SignerUtilities">
+            <summary>
+             Signer Utility class contains methods that can not be specifically grouped into other classes.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Security.SignerUtilities.GetObjectIdentifier(System.String)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Security.WrapperUtilities">
+            <remarks>
+             Utility class for creating IWrapper objects from their names/Oids
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Tsp.TimeStampRequest">
+            Base class for an RFC 3161 Time Stamp Request.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequest.#ctor(System.Byte[])">
+             Create a TimeStampRequest from the past in byte array.
+            
+             @param req byte array containing the request.
+             @throws IOException if the request is malformed.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequest.#ctor(System.IO.Stream)">
+             Create a TimeStampRequest from the past in input stream.
+            
+             @param in input stream containing the request.
+             @throws IOException if the request is malformed.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequest.Validate(System.Collections.IList,System.Collections.IList,System.Collections.IList)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequest.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="T:Org.BouncyCastle.Tsp.TimeStampRequestGenerator">
+            Generator for RFC 3161 Time Stamp Request objects.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequestGenerator.AddExtension(System.String,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            add a given extension field for the standard extensions tag (tag 3)
+            @throws IOException
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequestGenerator.AddExtension(System.String,System.Boolean,System.Byte[])">
+            add a given extension field for the standard extensions tag
+            The value parameter becomes the contents of the octet string associated
+            with the extension.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequestGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            add a given extension field for the standard extensions tag (tag 3)
+            @throws IOException
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequestGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,System.Byte[])">
+            add a given extension field for the standard extensions tag
+            The value parameter becomes the contents of the octet string associated
+            with the extension.
+        </member>
+        <member name="T:Org.BouncyCastle.Tsp.TimeStampResponse">
+            Base class for an RFC 3161 Time Stamp Response object.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampResponse.#ctor(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampResponse.#ctor(System.IO.Stream)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampResponse.Validate(Org.BouncyCastle.Tsp.TimeStampRequest)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampResponse.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="T:Org.BouncyCastle.Tsp.TimeStampResponseGenerator">
+            Generator for RFC 3161 Time Stamp Responses.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampResponseGenerator.Generate(Org.BouncyCastle.Tsp.TimeStampRequest,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Utilities.Date.DateTimeObject)">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampResponseGenerator.GenerateFailResponse(Org.BouncyCastle.Asn1.Cmp.PkiStatus,System.Int32,System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampToken.Validate(Org.BouncyCastle.X509.X509Certificate)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampToken.ToCmsSignedData">
+             Return the underlying CmsSignedData object.
+            
+             @return the underlying CMS structure.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampToken.GetEncoded">
+             Return a ASN.1 encoded byte stream representing the encoded object.
+            
+             @throws IOException if encoding fails.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampTokenGenerator.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String)">
+            basic creation - only the default attributes will be included here.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampTokenGenerator.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+            create with a signer with extra signed/unsigned attributes.
+        </member>
+        <member name="P:Org.BouncyCastle.Tsp.TimeStampTokenInfo.Nonce">
+            @return the nonce value, null if there isn't one.
+        </member>
+        <member name="T:Org.BouncyCastle.Tsp.TspAlgorithms">
+            Recognised hash algorithms for the time stamp protocol.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TspUtil.GetSignatureTimestamps(Org.BouncyCastle.Cms.SignerInformation)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TspUtil.ValidateCertificate(Org.BouncyCastle.X509.X509Certificate)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TspUtil.GetDigestAlgName(System.String)">
+            <summary>
+            Return the digest algorithm using one of the standard JCA string
+            representations rather than the algorithm identifier (if possible).
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Tsp.TspValidationException">
+            Exception thrown if a TSP request or response fails to validate.
+            <p>
+            If a failure code is associated with the exception it can be retrieved using
+            the getFailureCode() method.</p>
+        </member>
+        <member name="P:Org.BouncyCastle.Tsp.TspValidationException.FailureCode">
+             Return the failure code associated with this exception - if one is set.
+            
+             @return the failure code if set, -1 otherwise.
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Arrays">
+            <summary> General array utilities.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Arrays.AreEqual(System.Byte[],System.Byte[])">
+            <summary>
+            Are two arrays equal.
+            </summary>
+            <param name="a">Left side.</param>
+            <param name="b">Right side.</param>
+            <returns>True if equal.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Arrays.ConstantTimeAreEqual(System.Byte[],System.Byte[])">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.BigIntegers">
+            BigInteger utilities.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.BigIntegers.AsUnsignedByteArray(Org.BouncyCastle.Math.BigInteger)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.BigIntegers.CreateRandomInRange(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Security.SecureRandom)">
+            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]
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Date.DateTimeUtilities.DateTimeToUnixMs(System.DateTime)">
+            <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="T:System.ArgumentException">'dateTime' is before epoch.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Date.DateTimeUtilities.UnixMsToDateTime(System.Int64)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Date.DateTimeUtilities.CurrentUnixMs">
+            <summary>
+            Return the current number of milliseconds since the Unix epoch (1 Jan., 1970 UTC).
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64.Encode(System.Byte[])">
+             encode the input data producing a base 64 encoded byte array.
+            
+             @return a byte array containing the base 64 encoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64.Encode(System.Byte[],System.IO.Stream)">
+             Encode the byte data to base 64 writing it to the given output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64.Encode(System.Byte[],System.Int32,System.Int32,System.IO.Stream)">
+             Encode the byte data to base 64 writing it to the given output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64.Decode(System.Byte[])">
+             decode the base 64 encoded input data. It is assumed the input data is valid.
+            
+             @return a byte array representing the decoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64.Decode(System.String)">
+             decode the base 64 encoded string data - whitespace will be ignored.
+            
+             @return a byte array representing the decoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64.Decode(System.String,System.IO.Stream)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.IEncoder">
+            Encode and decode byte arrays (typically from binary to 7-bit ASCII
+            encodings).
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64Encoder.Encode(System.Byte[],System.Int32,System.Int32,System.IO.Stream)">
+             encode the input data producing a base 64 output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64Encoder.Decode(System.Byte[],System.Int32,System.Int32,System.IO.Stream)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64Encoder.DecodeString(System.String,System.IO.Stream)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.BufferedDecoder">
+            <summary>
+             A buffering class to allow translation from one format to another to
+                be done in discrete chunks.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.BufferedDecoder.#ctor(Org.BouncyCastle.Utilities.Encoders.ITranslator,System.Int32)">
+            <summary>
+            Create a buffered Decoder.
+            </summary>
+            <param name="translator">The translater to use.</param>
+            <param name="bufferSize">The size of the buffer.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.BufferedDecoder.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.BufferedDecoder.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.BufferedEncoder">
+            <summary>
+            A class that allows encoding of data using a specific encoder to be processed in chunks.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.BufferedEncoder.#ctor(Org.BouncyCastle.Utilities.Encoders.ITranslator,System.Int32)">
+            <summary>
+            Create.
+            </summary>
+            <param name="translator">The translator to use.</param>
+            <param name="bufferSize">Size of the chunks.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.BufferedEncoder.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.BufferedEncoder.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.Hex">
+            <summary>
+            Class to decode and encode Hex.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Encode(System.Byte[])">
+             encode the input data producing a Hex encoded byte array.
+            
+             @return a byte array containing the Hex encoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Encode(System.Byte[],System.Int32,System.Int32)">
+             encode the input data producing a Hex encoded byte array.
+            
+             @return a byte array containing the Hex encoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Encode(System.Byte[],System.IO.Stream)">
+             Hex encode the byte data writing it to the given output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Encode(System.Byte[],System.Int32,System.Int32,System.IO.Stream)">
+             Hex encode the byte data writing it to the given output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Decode(System.Byte[])">
+             decode the Hex encoded input data. It is assumed the input data is valid.
+            
+             @return a byte array representing the decoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Decode(System.String)">
+             decode the Hex encoded string data - whitespace will be ignored.
+            
+             @return a byte array representing the decoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Decode(System.String,System.IO.Stream)">
+             decode the Hex encoded string data writing it to the given output stream,
+             whitespace characters will be ignored.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexEncoder.Encode(System.Byte[],System.Int32,System.Int32,System.IO.Stream)">
+             encode the input data producing a Hex output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexEncoder.Decode(System.Byte[],System.Int32,System.Int32,System.IO.Stream)">
+             decode the Hex encoded byte data writing it to the given output stream,
+             whitespace characters will be ignored.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexEncoder.DecodeString(System.String,System.IO.Stream)">
+             decode the Hex encoded string data writing it to the given output stream,
+             whitespace characters will be ignored.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.HexTranslator">
+            <summary>
+            A hex translator.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.ITranslator">
+            <summary>
+            Translator interface.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexTranslator.GetEncodedBlockSize">
+            <summary>
+            Return encoded block size.
+            </summary>
+            <returns>2</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexTranslator.Encode(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexTranslator.GetDecodedBlockSize">
+            <summary>
+            Returns the decoded block size.
+            </summary>
+            <returns>1</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexTranslator.Decode(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.UrlBase64">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.UrlBase64.Encode(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.UrlBase64.Encode(System.Byte[],System.IO.Stream)">
+             Encode the byte data writing it to the given output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.UrlBase64.Decode(System.Byte[])">
+             Decode the URL safe base 64 encoded input data - white space will be ignored.
+            
+             @return a byte array representing the decoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.UrlBase64.Decode(System.Byte[],System.IO.Stream)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.UrlBase64.Decode(System.String)">
+             decode the URL safe base 64 encoded string data - whitespace will be ignored.
+            
+             @return a byte array representing the decoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.UrlBase64.Decode(System.String,System.IO.Stream)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.UrlBase64Encoder">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.IO.Pem.PemObjectParser.ParseObject(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+            <param name="obj">
+            A <see cref="T:Org.BouncyCastle.Utilities.IO.Pem.PemObject"/>
+            </param>
+            <returns>
+            A <see cref="T:System.Object"/>
+            </returns>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.IO.Streams.PipeAllLimited(System.IO.Stream,System.Int64,System.IO.Stream)">
+            <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="T:System.IO.Stream"/>
+            </param>
+            <param name="limit">
+            A <see cref="T:System.Int64"/>
+            </param>
+            <param name="outStr">
+            A <see cref="T:System.IO.Stream"/>
+            </param>
+            <returns>The number of bytes actually transferred, if not greater than <c>limit</c></returns>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Net.IPAddress.IsValid(System.String)">
+             Validate the given IPv4 or IPv6 address.
+            
+             @param address the IP address as a string.
+            
+             @return true if a valid address, false otherwise
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Net.IPAddress.IsValidWithNetMask(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Net.IPAddress.IsValidIPv4(System.String)">
+             Validate the given IPv4 address.
+             
+             @param address the IP address as a string.
+            
+             @return true if a valid IPv4 address, false otherwise
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Net.IPAddress.IsValidIPv6(System.String)">
+             Validate the given IPv6 address.
+            
+             @param address the IP address as a string.
+            
+             @return true if a valid IPv4 address, false otherwise
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Strings">
+            <summary> General string utilities.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Zlib.ZDeflaterOutputStream">
+            <summary>
+            Summary description for DeflaterOutputStream.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Zlib.ZInflaterInputStream">
+            <summary>
+            Summary description for DeflaterOutputStream.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.AttributeCertificateHolder">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.AttributeCertificateHolder.#ctor(System.Int32,System.String,System.String,System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.AttributeCertificateHolder.GetObjectDigest">
+             Returns the hash if an object digest info is used.
+            
+             @return The hash or <code>null</code> if no object digest info is set.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.AttributeCertificateHolder.GetEntityNames">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.AttributeCertificateHolder.GetIssuer">
+             Return the principals associated with the issuer attached to this holder
+            
+             @return an array of principals, null if no BaseCertificateID is set.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.AttributeCertificateHolder.DigestedObjectType">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.AttributeCertificateHolder.DigestAlgorithm">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.AttributeCertificateHolder.OtherObjectTypeID">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.AttributeCertificateHolder.SerialNumber">
+             Return the serial number associated with the issuer attached to this holder.
+            
+             @return the certificate serial number, null if no BaseCertificateID is set.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.AttributeCertificateIssuer">
+            Carrying class for an attribute certificate issuer.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.AttributeCertificateIssuer.#ctor(Org.BouncyCastle.Asn1.X509.AttCertIssuer)">
+             Set the issuer directly with the ASN.1 structure.
+            
+             @param issuer The issuer
+        </member>
+        <member name="M:Org.BouncyCastle.X509.AttributeCertificateIssuer.GetPrincipals">
+            <summary>Return any principal objects inside the attribute certificate issuer object.</summary>
+            <returns>An array of IPrincipal objects (usually X509Principal).</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.Extension.AuthorityKeyIdentifierStructure">
+            <remarks>A high level authority key identifier.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Extension.AuthorityKeyIdentifierStructure.#ctor(Org.BouncyCastle.Asn1.Asn1OctetString)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Extension.AuthorityKeyIdentifierStructure.#ctor(Org.BouncyCastle.X509.X509Certificate)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Extension.AuthorityKeyIdentifierStructure.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.Extension.SubjectKeyIdentifierStructure">
+            A high level subject key identifier.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Extension.SubjectKeyIdentifierStructure.#ctor(Org.BouncyCastle.Asn1.Asn1OctetString)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.IX509AttributeCertificate">
+            <remarks>Interface for an X.509 Attribute Certificate.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.IX509AttributeCertificate.GetAttributes">
+            <summary>Return the attributes contained in the attribute block in the certificate.</summary>
+            <returns>An array of attributes.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.IX509AttributeCertificate.GetAttributes(System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.IX509AttributeCertificate.GetEncoded">
+            <summary>Return an ASN.1 encoded byte array representing the attribute certificate.</summary>
+            <returns>An ASN.1 encoded byte array.</returns>
+            <exception cref="T:System.IO.IOException">If the certificate cannot be encoded.</exception>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.IX509AttributeCertificate.Version">
+            <summary>The version number for the certificate.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.IX509AttributeCertificate.SerialNumber">
+            <summary>The serial number for the certificate.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.IX509AttributeCertificate.NotBefore">
+            <summary>The UTC DateTime before which the certificate is not valid.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.IX509AttributeCertificate.NotAfter">
+            <summary>The UTC DateTime after which the certificate is not valid.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.IX509AttributeCertificate.Holder">
+            <summary>The holder of the certificate.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.IX509AttributeCertificate.Issuer">
+            <summary>The issuer details for the certificate.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.PrincipalUtilities">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.PrincipalUtilities.GetIssuerX509Principal(Org.BouncyCastle.X509.X509Certificate)">
+            <summary>Return the issuer of the given cert as an X509Principal.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.PrincipalUtilities.GetSubjectX509Principal(Org.BouncyCastle.X509.X509Certificate)">
+            <summary>Return the subject of the given cert as an X509Principal.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.PrincipalUtilities.GetIssuerX509Principal(Org.BouncyCastle.X509.X509Crl)">
+            <summary>Return the issuer of the given CRL as an X509Principal.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.Match(System.Object)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.AddTargetName(Org.BouncyCastle.Asn1.X509.GeneralName)">
+             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>)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.AddTargetName(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.SetTargetNames(System.Collections.IEnumerable)">
+            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)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.GetTargetNames">
+            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)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.AddTargetGroup(Org.BouncyCastle.Asn1.X509.GeneralName)">
+             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>)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.AddTargetGroup(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.SetTargetGroups(System.Collections.IEnumerable)">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.GetTargetGroups">
+             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)
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.AttributeCert">
+            <summary>The attribute certificate which must be matched.</summary>
+            <remarks>If <c>null</c> is given, any will do.</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.AttributeCertificateValid">
+            <summary>The criteria for validity</summary>
+            <remarks>If <c>null</c> is given any will do.</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.Holder">
+            <summary>The holder.</summary>
+            <remarks>If <c>null</c> is given any will do.</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.Issuer">
+            <summary>The issuer.</summary>
+            <remarks>If <c>null</c> is given any will do.</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.SerialNumber">
+            <summary>The serial number.</summary>
+            <remarks>If <c>null</c> is given any will do.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.Store.X509CertPairStoreSelector">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509CertPairStoreSelector.Match(System.Object)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CertPairStoreSelector.CertPair">
+            <summary>The certificate pair which is used for testing on equality.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CertPairStoreSelector.ForwardSelector">
+            <summary>The certificate selector for the forward part.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CertPairStoreSelector.ReverseSelector">
+            <summary>The certificate selector for the reverse part.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.Store.X509CollectionStore">
+            A simple collection backed store.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509CollectionStore.#ctor(System.Collections.ICollection)">
+             Basic constructor.
+            
+             @param collection - initial contents for the store, this is copied.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509CollectionStore.GetMatches(Org.BouncyCastle.X509.Store.IX509Selector)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.Store.X509CollectionStoreParameters">
+            <remarks>This class contains a collection for collection based <code>X509Store</code>s.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509CollectionStoreParameters.#ctor(System.Collections.ICollection)">
+            <summary>
+            Constructor.
+            <p>
+            The collection is copied.
+            </p>
+            </summary>
+            <param name="collection">The collection containing X.509 object types.</param>
+            <exception cref="T:System.ArgumentNullException">If collection is null.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509CollectionStoreParameters.GetCollection">
+            <summary>Returns a copy of the <code>ICollection</code>.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509CollectionStoreParameters.ToString">
+            <summary>Returns a formatted string describing the parameters.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.Issuers">
+            <summary>
+            An <code>ICollection</code> of <code>X509Name</code> objects
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.AttrCertChecking">
+             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()
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.CompleteCrlEnabled">
+             If <code>true</code> only complete CRLs are returned. Defaults to
+             <code>false</code>.
+            
+             @return <code>true</code> if only complete CRLs are returned.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.DeltaCrlIndicatorEnabled">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.IssuingDistributionPoint">
+             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()
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.IssuingDistributionPointEnabled">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.MaxBaseCrlNumber">
+             The maximum base CRL number. Defaults to <code>null</code>.
+            
+             @return Returns the maximum base CRL number.
+             @see #setMaxBaseCRLNumber(BigInteger)
+        </member>
+        <member name="T:Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory">
+            <summary>
+            A factory to produce Public Key Info Objects.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <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="T:System.Exception">Throw exception if object provided is not one of the above.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509AttrCertParser.ReadAttrCert(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509AttrCertParser.ReadAttrCerts(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509AttrCertParser.ReadAttrCert(System.IO.Stream)">
+            Generates a certificate object and initializes it with the data
+            read from the input stream inStream.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509AttrCertParser.ReadAttrCerts(System.IO.Stream)">
+            Returns a (possibly empty) collection view of the certificates
+            read from the given input stream inStream.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509Attribute">
+            Class for carrying the values in an X.509 Attribute.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Attribute.#ctor(Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param at an object representing an attribute.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Attribute.#ctor(System.String,Org.BouncyCastle.Asn1.Asn1Encodable)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Attribute.#ctor(System.String,Org.BouncyCastle.Asn1.Asn1EncodableVector)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509Certificate">
+            <summary>
+            An Object representing an X509 Certificate.
+            Has static methods for loading Certificates encoded in many forms that return X509Certificate Objects.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.IsValid(System.DateTime)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.CheckValidity">
+            <summary>
+            Checks if the current date is within certificate's validity period.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.CheckValidity(System.DateTime)">
+            <summary>
+            Checks if the given date is within certificate's validity period.
+            </summary>
+            <exception cref="T:Org.BouncyCastle.Security.Certificates.CertificateExpiredException">if the certificate is expired by given date</exception>
+            <exception cref="T:Org.BouncyCastle.Security.Certificates.CertificateNotYetValidException">if the certificate is not yet valid on given date</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.GetTbsCertificate">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.GetSignature">
+            <summary>
+            The signature.
+            </summary>
+            <returns>A byte array containg the signature of the certificate.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.GetSigAlgParams">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.GetKeyUsage">
+            <summary>
+            Get a key usage guidlines.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.GetPublicKey">
+            <summary>
+            Get the public key of the subject of the certificate.
+            </summary>
+            <returns>The public key parameters.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.GetEncoded">
+            <summary>
+            Return a Der encoded version of this certificate.
+            </summary>
+            <returns>A byte array.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.Verify(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <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="T:System.Exception">If key submitted is not of the above nominated types.</exception>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.IsValidNow">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.Version">
+            <summary>
+            Return the certificate's version.
+            </summary>
+            <returns>An integer whose value Equals the version of the cerficate.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.SerialNumber">
+            <summary>
+            Return a <see cref="T:Org.BouncyCastle.Math.BigInteger">BigInteger</see> containing the serial number.
+            </summary>
+            <returns>The Serial number.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.IssuerDN">
+            <summary>
+            Get the Issuer Distinguished Name. (Who signed the certificate.)
+            </summary>
+            <returns>And X509Object containing name and value pairs.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.SubjectDN">
+            <summary>
+            Get the subject of this certificate.
+            </summary>
+            <returns>An X509Name object containing name and value pairs.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.NotBefore">
+            <summary>
+            The time that this certificate is valid from.
+            </summary>
+            <returns>A DateTime object representing that time in the local time zone.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.NotAfter">
+            <summary>
+            The time that this certificate is valid up to.
+            </summary>
+            <returns>A DateTime object representing that time in the local time zone.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.SigAlgName">
+            <summary>
+            A meaningful version of the Signature Algorithm. (EG SHA1WITHRSA)
+            </summary>
+            <returns>A sting representing the signature algorithm.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.SigAlgOid">
+            <summary>
+            Get the Signature Algorithms Object ID.
+            </summary>
+            <returns>A string containg a '.' separated object id.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.IssuerUniqueID">
+            <summary>
+            Get the issuers UID.
+            </summary>
+            <returns>A DerBitString.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.SubjectUniqueID">
+            <summary>
+            Get the subjects UID.
+            </summary>
+            <returns>A DerBitString.</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509CertificatePair">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertificatePair.#ctor(Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.X509.X509Certificate)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertificatePair.#ctor(Org.BouncyCastle.Asn1.X509.CertificatePair)">
+            <summary>Constructor from a ASN.1 CertificatePair structure.</summary>
+            <param name="pair">The <c>CertificatePair</c> ASN.1 object.</param>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509CertificatePair.Forward">
+            <summary>Returns the certificate from the other CA to this CA.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509CertificatePair.Reverse">
+            <summary>Returns the certificate from this CA to the other CA.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509CertificateParser">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertificateParser.ReadCertificate(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertificateParser.ReadCertificates(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertificateParser.ReadCertificate(System.IO.Stream)">
+            Generates a certificate object and initializes it with the data
+            read from the input stream inStream.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertificateParser.ReadCertificates(System.IO.Stream)">
+            Returns a (possibly empty) collection view of the certificates
+            read from the given input stream inStream.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertPairParser.ReadCertPair(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertPairParser.ReadCertPairs(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509Crl">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Crl.ToString">
+             Returns a string representation of this CRL.
+            
+             @return a string representation of this CRL.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Crl.IsRevoked(Org.BouncyCastle.X509.X509Certificate)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509CrlEntry">
+             The following extensions are listed in RFC 2459 as relevant to CRL Entries
+            
+             ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+             (critical)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CrlEntry.#ctor(Org.BouncyCastle.Asn1.X509.CrlEntry,System.Boolean,Org.BouncyCastle.Asn1.X509.X509Name)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CrlParser.ReadCrl(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CrlParser.ReadCrls(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CrlParser.ReadCrl(System.IO.Stream)">
+            Generates a certificate revocation list (CRL) object and initializes
+            it with the data read from the input stream inStream.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CrlParser.ReadCrls(System.IO.Stream)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509KeyUsage">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509KeyUsage.#ctor(System.Int32)">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509SignatureUtilities.GetDigestAlgName(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            Return the digest algorithm using one of the standard JCA string
+            representations rather than the algorithm identifier (if possible).
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509V1CertificateGenerator">
+            <summary>
+            Class to Generate X509V1 Certificates.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.#ctor">
+            <summary>
+            Default Constructor.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.Reset">
+            <summary>
+            Reset the generator.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetSerialNumber(Org.BouncyCastle.Math.BigInteger)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetIssuerDN(Org.BouncyCastle.Asn1.X509.X509Name)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetNotBefore(System.DateTime)">
+            <summary>
+            Set the date that this certificate is to be valid from.
+            </summary>
+            <param name="date"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetNotAfter(System.DateTime)">
+            <summary>
+            Set the date after which this certificate will no longer be valid.
+            </summary>
+            <param name="date"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetSubjectDN(Org.BouncyCastle.Asn1.X509.X509Name)">
+            <summary>
+            Set the subject distinguished name.
+            The subject describes the entity associated with the public key.
+            </summary>
+            <param name="subject"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetPublicKey(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <summary>
+            Set the public key that this certificate identifies.
+            </summary>
+            <param name="publicKey"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetSignatureAlgorithm(System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509V1CertificateGenerator.SignatureAlgNames">
+            <summary>
+            Allows enumeration of the signature names supported by the generator.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509V2AttributeCertificate">
+            <summary>An implementation of a version 2 X.509 Attribute Certificate.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator">
+            <remarks>Class to produce an X.509 Version 2 AttributeCertificate.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.Reset">
+            <summary>Reset the generator</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.SetHolder(Org.BouncyCastle.X509.AttributeCertificateHolder)">
+            <summary>Set the Holder of this Attribute Certificate.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.SetIssuer(Org.BouncyCastle.X509.AttributeCertificateIssuer)">
+            <summary>Set the issuer.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.SetSerialNumber(Org.BouncyCastle.Math.BigInteger)">
+            <summary>Set the serial number for the certificate.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.SetSignatureAlgorithm(System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.AddAttribute(Org.BouncyCastle.X509.X509Attribute)">
+            <summary>Add an attribute.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.AddExtension(System.String,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            <summary>Add a given extension field for the standard extensions tag.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.AddExtension(System.String,System.Boolean,System.Byte[])">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <summary>
+            Generate an X509 certificate, based on the current issuer and subject.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Security.SecureRandom)">
+            <summary>
+            Generate an X509 certificate, based on the current issuer and subject,
+            using the supplied source of randomness, if required.
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.SignatureAlgNames">
+            <summary>
+            Allows enumeration of the signature names supported by the generator.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509V2CrlGenerator">
+            class to produce an X.509 Version 2 CRL.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.Reset">
+            reset the generator
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.SetIssuerDN(Org.BouncyCastle.Asn1.X509.X509Name)">
+            Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+            certificate.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddCrlEntry(Org.BouncyCastle.Math.BigInteger,System.DateTime,System.Int32)">
+             Reason being as indicated by CrlReason, i.e. CrlReason.KeyCompromise
+             or 0 if CrlReason is not to be used
+            
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddCrlEntry(Org.BouncyCastle.Math.BigInteger,System.DateTime,System.Int32,System.DateTime)">
+             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
+            
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddCrlEntry(Org.BouncyCastle.Math.BigInteger,System.DateTime,Org.BouncyCastle.Asn1.X509.X509Extensions)">
+             Add a CRL entry with extensions.
+            
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddCrl(Org.BouncyCastle.X509.X509Crl)">
+             Add the CRLEntry objects contained in a previous CRL.
+            
+             @param other the X509Crl to source the other entries from.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.SetSignatureAlgorithm(System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddExtension(System.String,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            add a given extension field for the standard extensions tag (tag 0)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            add a given extension field for the standard extensions tag (tag 0)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddExtension(System.String,System.Boolean,System.Byte[])">
+            add a given extension field for the standard extensions tag (tag 0)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,System.Byte[])">
+            add a given extension field for the standard extensions tag (tag 0)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <summary>Generate an X509 CRL, based on the current issuer and subject.</summary>
+            <param name="privateKey">The key used for signing.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509V2CrlGenerator.SignatureAlgNames">
+            <summary>
+            Allows enumeration of the signature names supported by the generator.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509V3CertificateGenerator">
+            <summary>
+            A class to Generate Version 3 X509Certificates.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.Reset">
+            <summary>
+            Reset the Generator.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetSerialNumber(Org.BouncyCastle.Math.BigInteger)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetIssuerDN(Org.BouncyCastle.Asn1.X509.X509Name)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetNotBefore(System.DateTime)">
+            <summary>
+            Set the date that this certificate is to be valid from.
+            </summary>
+            <param name="date"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetNotAfter(System.DateTime)">
+            <summary>
+            Set the date after which this certificate will no longer be valid.
+            </summary>
+            <param name="date"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetSubjectDN(Org.BouncyCastle.Asn1.X509.X509Name)">
+            <summary>
+            Set the DN of the entity that this certificate is about.
+            </summary>
+            <param name="subject"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetPublicKey(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <summary>
+            Set the public key that this certificate identifies.
+            </summary>
+            <param name="publicKey"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetSignatureAlgorithm(System.String)">
+            <summary>
+            Set the signature algorithm that will be used to sign this certificate.
+            </summary>
+            <param name="signatureAlgorithm"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetSubjectUniqueID(System.Boolean[])">
+            <summary>
+            Set the subject unique ID - note: it is very rare that it is correct to do this.
+            </summary>
+            <param name="uniqueID"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetIssuerUniqueID(System.Boolean[])">
+            <summary>
+            Set the issuer unique ID - note: it is very rare that it is correct to do this.
+            </summary>
+            <param name="uniqueID"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.AddExtension(System.String,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.AddExtension(System.String,System.Boolean,System.Byte[])">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,System.Byte[])">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.CopyAndAddExtension(System.String,System.Boolean,Org.BouncyCastle.X509.X509Certificate)">
+            <summary>
+            Add a given extension field for the standard extensions tag (tag 3),
+            copying the extension value from another certificate.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.CopyAndAddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,Org.BouncyCastle.X509.X509Certificate)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <summary>
+            Generate an X509Certificate.
+            </summary>
+            <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
+            <returns>An X509Certificate.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509V3CertificateGenerator.SignatureAlgNames">
+            <summary>
+            Allows enumeration of the signature names supported by the generator.
+            </summary>
+        </member>
+    </members>
+</doc>
diff --git a/Crypto/doc/wp7/crypto.xml b/Crypto/doc/wp7/crypto.xml
new file mode 100644
index 000000000..f1cf2f391
--- /dev/null
+++ b/Crypto/doc/wp7/crypto.xml
@@ -0,0 +1,19296 @@
+<?xml version="1.0"?>
+<doc>
+    <assembly>
+        <name>crypto</name>
+    </assembly>
+    <members>
+        <member name="T:Org.BouncyCastle.Apache.Bzip2.BZip2Constants">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Apache.Bzip2.CBZip2InputStream">
+             An input stream that decompresses from the BZip2 format (with the file
+             header chars) to be read as any other stream.
+            
+             @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+            
+             <b>NB:</b> note this class has been modified to read the leading BZ from the
+             start of the BZIP2 stream to make it compatible with other PGP programs.
+        </member>
+        <member name="T:Org.BouncyCastle.Apache.Bzip2.CBZip2OutputStream">
+             An output stream that compresses into the BZip2 format (with the file
+             header chars) into another stream.
+            
+             @author <a href="mailto:keiron@aftexsw.com">Keiron Liddle</a>
+            
+             TODO:    Update to BZip2 1.0.1
+             <b>NB:</b> note this class has been modified to add a leading BZ to the
+             start of the BZIP2 stream to make it compatible with other PGP programs.
+        </member>
+        <member name="M:Org.BouncyCastle.Apache.Bzip2.CBZip2OutputStream.WriteByte(System.Byte)">
+            
+             modified by Oliver Merkel, 010128
+            
+        </member>
+        <member name="T:Org.BouncyCastle.Apache.Bzip2.CRC">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Encodable.GetDerEncoded">
+             Return the DER encoding of the object, null if the DER encoding can not be made.
+            
+             @return a DER byte array, null otherwise.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Asn1InputStream">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1InputStream.#ctor(System.IO.Stream,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1InputStream.#ctor(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1InputStream.BuildObject(System.Int32,System.Int32,System.Int32)">
+            build an object given its tag and the number of bytes to construct it from.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Asn1Null">
+            A Null object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Object.FromByteArray(System.Byte[])">
+            <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="T:System.IO.IOException">If there is a problem parsing the data.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Object.FromStream(System.IO.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="T:System.IO.IOException">If there is a problem parsing the data.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1OctetString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1OctetString.GetInstance(System.Object)">
+             return an Octet string from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1OctetString.#ctor(System.Byte[])">
+            @param string the octets making up the octet string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Sequence.GetInstance(System.Object)">
+             return an Asn1Sequence from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Sequence.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             Return an ASN1 sequence from a tagged object. There is a special
+             case here, if an object appears to have been explicitly tagged on
+             reading but we were expecting it to be implicitly tagged in the
+             normal course of events it indicates that we lost the surrounding
+             sequence - so we need to add it back (this will happen if the tagged
+             object is a sequence that contains other sequences). If you are
+             dealing with implicitly tagged sequences you really <b>should</b>
+             be using this method.
+            
+             @param obj the tagged object.
+             @param explicitly true if the object is meant to be explicitly tagged,
+                      false otherwise.
+             @exception ArgumentException if the tagged object cannot
+                      be converted.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Asn1Sequence.Item(System.Int32)">
+             return the object at the sequence position indicated by index.
+            
+             @param index the sequence number (starting at zero) of the object
+             @return the object at the sequence position indicated by index.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Set.GetInstance(System.Object)">
+             return an ASN1Set from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Set.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             Return an ASN1 set from a tagged object. There is a special
+             case here, if an object appears to have been explicitly tagged on
+             reading but we were expecting it to be implicitly tagged in the
+             normal course of events it indicates that we lost the surrounding
+             set - so we need to add it back (this will happen if the tagged
+             object is a sequence that contains other sequences). If you are
+             dealing with implicitly tagged sets you really <b>should</b>
+             be using this method.
+            
+             @param obj the tagged object.
+             @param explicitly true if the object is meant to be explicitly tagged
+                      false otherwise.
+             @exception ArgumentException if the tagged object cannot
+                      be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1Set.LessThanOrEqual(System.Byte[],System.Byte[])">
+            return true if a &lt;= b (arrays are assumed padded with zeros).
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Asn1Set.Item(System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Asn1TaggedObject">
+            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).
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1TaggedObject.#ctor(System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param tagNo the tag number for this object.
+            @param obj the tagged object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1TaggedObject.#ctor(System.Boolean,System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param explicitly true if the object is explicitly tagged.
+            @param tagNo the tag number for this object.
+            @param obj the tagged object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1TaggedObject.IsExplicit">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1TaggedObject.GetObject">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Asn1TaggedObject.GetObjectParser(System.Int32,System.Boolean)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerApplicationSpecific">
+            Base class for an application specific object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerApplicationSpecific.GetObject">
+             Return the enclosed object assuming explicit tagging.
+            
+             @return  the resulting object
+             @throws IOException if reconstruction fails.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerApplicationSpecific.GetObject(System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.BerNull">
+            A BER Null object.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerNull">
+            A Null object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerOctetString.#ctor(System.Byte[])">
+            <param name="str">The octets making up the octet string.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerOctetString.ToBytes(System.Collections.IEnumerable)">
+            convert a vector of octet strings into a single byte string
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerOctetString.#ctor(System.Byte[])">
+            <param name="str">The octets making up the octet string.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerOctetString.GetEnumerator">
+            return the DER octets that make up this string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerSequence.#ctor">
+            create an empty sequence
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerSequence.#ctor(Org.BouncyCastle.Asn1.Asn1Encodable)">
+            create a sequence containing one object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerSequence.#ctor(Org.BouncyCastle.Asn1.Asn1EncodableVector)">
+            create a sequence containing a vector of objects.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerSequence.#ctor">
+            create an empty sequence
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerSequence.#ctor(Org.BouncyCastle.Asn1.Asn1Encodable)">
+            create a sequence containing one object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerSequence.#ctor(Org.BouncyCastle.Asn1.Asn1EncodableVector)">
+            create a sequence containing a vector of objects.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerSet">
+            A Der encoded set object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerSet.#ctor">
+            create an empty set
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerSet.#ctor(Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param obj - a single object that makes up the set.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerSet.#ctor(Org.BouncyCastle.Asn1.Asn1EncodableVector)">
+            @param v - a vector of objects making up the set.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerSet.#ctor">
+            create an empty sequence
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerSet.#ctor(Org.BouncyCastle.Asn1.Asn1Encodable)">
+            create a set containing one object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerSet.#ctor(Org.BouncyCastle.Asn1.Asn1EncodableVector)">
+            create a set containing a vector of objects.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.BerTaggedObject">
+            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).
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerTaggedObject">
+            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).
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerTaggedObject.#ctor(System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param tagNo the tag number for this object.
+            @param obj the tagged object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerTaggedObject.#ctor(System.Boolean,System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param explicitly true if an explicitly tagged object.
+            @param tagNo the tag number for this object.
+            @param obj the tagged object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerTaggedObject.#ctor(System.Int32)">
+            create an implicitly tagged object that contains a zero
+            length sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerTaggedObject.#ctor(System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param tagNo the tag number for this object.
+            @param obj the tagged object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerTaggedObject.#ctor(System.Boolean,System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param explicitly true if an explicitly tagged object.
+            @param tagNo the tag number for this object.
+            @param obj the tagged object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.BerTaggedObject.#ctor(System.Int32)">
+            create an implicitly tagged object that contains a zero
+            length sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CAKeyUpdAnnContent.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CertConfirmContent.ToAsn1Object">
+            <pre>
+            CertConfirmContent ::= SEQUENCE OF CertStatus
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CertifiedKeyPair.ToAsn1Object">
+            <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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IAsn1Choice">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CertOrEncCert.ToAsn1Object">
+            <pre>
+            CertOrEncCert ::= CHOICE {
+                                 certificate     [0] CMPCertificate,
+                                 encryptedCert   [1] EncryptedValue
+                      }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CertRepMessage.ToAsn1Object">
+            <pre>
+            CertRepMessage ::= SEQUENCE {
+                                     caPubs       [1] SEQUENCE SIZE (1..MAX) OF CMPCertificate
+                                                                                        OPTIONAL,
+                                     response         SEQUENCE OF CertResponse
+            }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CertResponse.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CertStatus.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.Challenge.ToAsn1Object">
+             <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CmpCertificate.#ctor(Org.BouncyCastle.Asn1.X509.AttributeCertificate)">
+            Note: the addition of attribute certificates is a BC extension.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CmpCertificate.ToAsn1Object">
+             <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.CrlAnnContent.ToAsn1Object">
+            <pre>
+            CrlAnnContent ::= SEQUENCE OF CertificateList
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.ErrorMsgContent.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.GenMsgContent.ToAsn1Object">
+            <pre>
+            GenMsgContent ::= SEQUENCE OF InfoTypeAndValue
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.GenRepContent.ToAsn1Object">
+            <pre>
+            GenRepContent ::= SEQUENCE OF InfoTypeAndValue
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cmp.InfoTypeAndValue">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.InfoTypeAndValue.ToAsn1Object">
+            <pre>
+            InfoTypeAndValue ::= SEQUENCE {
+                                    infoType               OBJECT IDENTIFIER,
+                                    infoValue              ANY DEFINED BY infoType  OPTIONAL
+            }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.KeyRecRepContent.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.OobCertHash.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PbmParameter.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiBody.#ctor(System.Int32,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            Creates a new PkiBody.
+            @param type one of the TYPE_* constants
+            @param content message content
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiBody.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiConfirmContent.ToAsn1Object">
+            <pre>
+            PkiConfirmContent ::= NULL
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cmp.PkiFailureInfo">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IAsn1String">
+            basic interface for Der string objects.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBitString.GetPadBits(System.Int32)">
+            return the correct number of pad bits for a bit string defined in
+            a 32 bit constant
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBitString.GetBytes(System.Int32)">
+            return the correct number of bytes for a bit string defined in
+            a 32 bit constant
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBitString.GetInstance(System.Object)">
+             return a Bit string from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBitString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBitString.#ctor(System.Byte[],System.Int32)">
+            @param data the octets making up the bit string.
+            @param padBits the number of extra bits at the end of the string.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.DerBitString.IntValue">
+            @return the value of the bit string as an int (truncating if necessary)
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiFailureInfo.#ctor(System.Int32)">
+            Basic constructor.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiFreeText.ToAsn1Object">
+            <pre>
+            PkiFreeText ::= SEQUENCE SIZE (1..MAX) OF UTF8String
+            </pre>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Cmp.PkiFreeText.Size">
+             Return the number of string elements present.
+            
+             @return number of elements present.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Cmp.PkiFreeText.Item(System.Int32)">
+             Return the UTF8STRING at index.
+            
+             @param index index of the string of interest
+             @return the string at index.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.Cmp.PkiHeader.NULL_NAME">
+            Value for a "null" recipient or sender.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiHeader.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiHeaderBuilder.Build">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiMessage.#ctor(Org.BouncyCastle.Asn1.Cmp.PkiHeader,Org.BouncyCastle.Asn1.Cmp.PkiBody,Org.BouncyCastle.Asn1.DerBitString,Org.BouncyCastle.Asn1.Cmp.CmpCertificate[])">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiMessage.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiMessages.ToAsn1Object">
+            <pre>
+            PkiMessages ::= SEQUENCE SIZE (1..MAX) OF PkiMessage
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiStatusInfo.#ctor(System.Int32)">
+            @param status
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiStatusInfo.#ctor(System.Int32,Org.BouncyCastle.Asn1.Cmp.PkiFreeText)">
+            @param status
+            @param statusString
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PkiStatusInfo.ToAsn1Object">
+             <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PollRepContent.ToAsn1Object">
+            <pre>
+            PollRepContent ::= SEQUENCE OF SEQUENCE {
+                    certReqId              INTEGER,
+                    checkAfter             INTEGER,  -- time in seconds
+                    reason                 PKIFreeText OPTIONAL
+                }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PollReqContent.ToAsn1Object">
+            <pre>
+            PollReqContent ::= SEQUENCE OF SEQUENCE {
+                                   certReqId              INTEGER
+            }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PopoDecKeyChallContent.ToAsn1Object">
+            <pre>
+            PopoDecKeyChallContent ::= SEQUENCE OF Challenge
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.PopoDecKeyRespContent.ToAsn1Object">
+            <pre>
+            PopoDecKeyRespContent ::= SEQUENCE OF INTEGER
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.ProtectedPart.ToAsn1Object">
+            <pre>
+            ProtectedPart ::= SEQUENCE {
+                               header    PKIHeader,
+                               body      PKIBody
+            }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.RevAnnContent.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.RevDetails.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.RevRepContent.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cmp.RevReqContent.ToAsn1Object">
+            <pre>
+            RevReqContent ::= SEQUENCE OF RevDetails
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Attribute.GetInstance(System.Object)">
+             return an Attribute object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Attribute.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Attribute ::= SEQUENCE {
+                attrType OBJECT IDENTIFIER,
+                attrValues SET OF AttributeValue
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Attributes.ToAsn1Object">
+            <pre>
+            Attributes ::=
+              SET SIZE(1..MAX) OF Attribute -- according to RFC 5652
+            </pre>
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AttributeTable.GetAll(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be
+             empty if there are no attributes of the required type present.
+            
+             @param oid type of attribute required.
+             @return a vector of all the attributes found of type oid.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AttributeTable.Add(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.Asn1Encodable)">
+             Return a new table with the passed in attribute added.
+            
+             @param attrType
+             @param attrValue
+             @return
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Cms.AttributeTable.Item(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            <summary>Return the first attribute matching the given OBJECT IDENTIFIER</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AuthenticatedData.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AuthenticatedData.GetInstance(System.Object)">
+             return an AuthenticatedData object from the given object.
+            
+             @param obj the object we want converted.
+             @throws ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AuthenticatedData.ToAsn1Object">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.AuthenticatedDataParser">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AuthEnvelopedData.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AuthEnvelopedData.GetInstance(System.Object)">
+             return an AuthEnvelopedData object from the given object.
+            
+             @param obj the object we want converted.
+             @throws ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.AuthEnvelopedData.ToAsn1Object">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.AuthEnvelopedDataParser">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.CompressedData">
+            RFC 3274 - CMS Compressed Data.
+            <pre>
+            CompressedData ::= Sequence {
+             version CMSVersion,
+             compressionAlgorithm CompressionAlgorithmIdentifier,
+             encapContentInfo EncapsulatedContentInfo
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.CompressedData.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.CompressedData.GetInstance(System.Object)">
+             return a CompressedData object from the given object.
+            
+             @param _obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.CompressedDataParser">
+            RFC 3274 - CMS Compressed Data.
+            <pre>
+            CompressedData ::= SEQUENCE {
+             version CMSVersion,
+             compressionAlgorithm CompressionAlgorithmIdentifier,
+             encapContentInfo EncapsulatedContentInfo
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.ContentInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            ContentInfo ::= Sequence {
+                     contentType ContentType,
+                     content
+                     [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.ContentInfoParser">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            ContentInfo ::= SEQUENCE {
+                     contentType ContentType,
+                     content
+                     [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Ecc.MQVuserKeyingMaterial.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Ecc.MQVuserKeyingMaterial.GetInstance(System.Object)">
+             return an AuthEnvelopedData object from the given object.
+            
+             @param obj the object we want converted.
+             @throws ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Ecc.MQVuserKeyingMaterial.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            MQVuserKeyingMaterial ::= SEQUENCE {
+              ephemeralPublicKey OriginatorPublicKey,
+              addedukm [0] EXPLICIT UserKeyingMaterial OPTIONAL  }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.EncryptedContentInfo.GetInstance(System.Object)">
+             return an EncryptedContentInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.EncryptedContentInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            EncryptedContentInfo ::= Sequence {
+                contentType ContentType,
+                contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+                encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.EncryptedContentInfoParser">
+            <pre>
+            EncryptedContentInfo ::= SEQUENCE {
+                contentType ContentType,
+                contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+                encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.EncryptedData.ToAsn1Object">
+            <pre>
+                  EncryptedData ::= SEQUENCE {
+                                version CMSVersion,
+                                encryptedContentInfo EncryptedContentInfo,
+                                unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.EnvelopedData.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             return an EnvelopedData 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.EnvelopedData.GetInstance(System.Object)">
+             return an EnvelopedData object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.EnvelopedData.ToAsn1Object">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.EnvelopedDataParser">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KekIdentifier.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KekIdentifier.GetInstance(System.Object)">
+             return a KekIdentifier object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KekIdentifier.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            KekIdentifier ::= Sequence {
+                keyIdentifier OCTET STRING,
+                date GeneralizedTime OPTIONAL,
+                other OtherKeyAttribute OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KekRecipientInfo.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KekRecipientInfo.GetInstance(System.Object)">
+             return a KekRecipientInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KekRecipientInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            KekRecipientInfo ::= Sequence {
+                version CMSVersion,  -- always set to 4
+                kekID KekIdentifier,
+                keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier,
+                encryptedKey EncryptedKey
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyAgreeRecipientIdentifier.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyAgreeRecipientIdentifier.GetInstance(System.Object)">
+             return an KeyAgreeRecipientIdentifier object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyAgreeRecipientIdentifier.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            KeyAgreeRecipientIdentifier ::= CHOICE {
+                issuerAndSerialNumber IssuerAndSerialNumber,
+                rKeyId [0] IMPLICIT RecipientKeyIdentifier
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyAgreeRecipientInfo.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyAgreeRecipientInfo.GetInstance(System.Object)">
+             return a KeyAgreeRecipientInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyAgreeRecipientInfo.ToAsn1Object">
+                     * 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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyTransRecipientInfo.GetInstance(System.Object)">
+             return a KeyTransRecipientInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.KeyTransRecipientInfo.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.MetaData.ToAsn1Object">
+            <pre>
+            MetaData ::= SEQUENCE {
+              hashProtected        BOOLEAN,
+              fileName             UTF8String OPTIONAL,
+              mediaType            IA5String OPTIONAL,
+              otherMetaData        Attributes OPTIONAL
+            }
+            </pre>
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorIdentifierOrKey.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorIdentifierOrKey.GetInstance(System.Object)">
+             return an OriginatorIdentifierOrKey object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorIdentifierOrKey.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <pre>
+             OriginatorIdentifierOrKey ::= CHOICE {
+                 issuerAndSerialNumber IssuerAndSerialNumber,
+                 subjectKeyIdentifier [0] SubjectKeyIdentifier,
+                 originatorKey [1] OriginatorPublicKey
+             }
+            
+             SubjectKeyIdentifier ::= OCTET STRING
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorInfo.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorInfo.GetInstance(System.Object)">
+             return an OriginatorInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            OriginatorInfo ::= Sequence {
+                certs [0] IMPLICIT CertificateSet OPTIONAL,
+                crls [1] IMPLICIT CertificateRevocationLists OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorPublicKey.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorPublicKey.GetInstance(System.Object)">
+             return an OriginatorPublicKey object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OriginatorPublicKey.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            OriginatorPublicKey ::= Sequence {
+                algorithm AlgorithmIdentifier,
+                publicKey BIT STRING
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OtherKeyAttribute.GetInstance(System.Object)">
+             return an OtherKeyAttribute object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OtherKeyAttribute.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            OtherKeyAttribute ::= Sequence {
+                keyAttrId OBJECT IDENTIFIER,
+                keyAttr ANY DEFINED BY keyAttrId OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OtherRecipientInfo.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             return a OtherRecipientInfo 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OtherRecipientInfo.GetInstance(System.Object)">
+             return a OtherRecipientInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.OtherRecipientInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            OtherRecipientInfo ::= Sequence {
+               oriType OBJECT IDENTIFIER,
+               oriValue ANY DEFINED BY oriType }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.PasswordRecipientInfo.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.PasswordRecipientInfo.GetInstance(System.Object)">
+             return a PasswordRecipientInfo object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.PasswordRecipientInfo.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientEncryptedKey.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientEncryptedKey.GetInstance(System.Object)">
+             return a RecipientEncryptedKey object from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientEncryptedKey.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            RecipientEncryptedKey ::= SEQUENCE {
+                rid KeyAgreeRecipientIdentifier,
+                encryptedKey EncryptedKey
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientIdentifier.GetInstance(System.Object)">
+             return a RecipientIdentifier object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientIdentifier.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <pre>
+             RecipientIdentifier ::= CHOICE {
+                 issuerAndSerialNumber IssuerAndSerialNumber,
+                 subjectKeyIdentifier [0] SubjectKeyIdentifier
+             }
+            
+             SubjectKeyIdentifier ::= OCTET STRING
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientInfo.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientKeyIdentifier.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientKeyIdentifier.GetInstance(System.Object)">
+             return a RecipientKeyIdentifier object from the given object.
+            
+             @param _obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.RecipientKeyIdentifier.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <pre>
+             RecipientKeyIdentifier ::= Sequence {
+                 subjectKeyIdentifier SubjectKeyIdentifier,
+                 date GeneralizedTime OPTIONAL,
+                 other OtherKeyAttribute OPTIONAL
+             }
+            
+             SubjectKeyIdentifier ::= OCTET STRING
+             </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.SignedData">
+            a signed data object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.SignedData.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            SignedData ::= Sequence {
+                version CMSVersion,
+                digestAlgorithms DigestAlgorithmIdentifiers,
+                encapContentInfo EncapsulatedContentInfo,
+                certificates [0] IMPLICIT CertificateSet OPTIONAL,
+                crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+                signerInfos SignerInfos
+              }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Cms.SignedDataParser">
+            <pre>
+            SignedData ::= SEQUENCE {
+                version CMSVersion,
+                digestAlgorithms DigestAlgorithmIdentifiers,
+                encapContentInfo EncapsulatedContentInfo,
+                certificates [0] IMPLICIT CertificateSet OPTIONAL,
+                crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+                signerInfos SignerInfos
+              }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.SignerIdentifier.GetInstance(System.Object)">
+             return a SignerIdentifier object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.SignerIdentifier.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <pre>
+             SignerIdentifier ::= CHOICE {
+                 issuerAndSerialNumber IssuerAndSerialNumber,
+                 subjectKeyIdentifier [0] SubjectKeyIdentifier
+             }
+            
+             SubjectKeyIdentifier ::= OCTET STRING
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.SignerInfo.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <pre>
+              SignerInfo ::= Sequence {
+                  version Version,
+                  SignerIdentifier sid,
+                  digestAlgorithm DigestAlgorithmIdentifier,
+                  authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
+                  digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+                  encryptedDigest EncryptedDigest,
+                  unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+              }
+            
+              EncryptedDigest ::= OCTET STRING
+            
+              DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+            
+              DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Time.#ctor(System.DateTime)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.Time.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Time ::= CHOICE {
+                        utcTime        UTCTime,
+                        generalTime    GeneralizedTime }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.TimeStampAndCrl.ToAsn1Object">
+            <pre>
+            TimeStampAndCRL ::= SEQUENCE {
+                timeStamp   TimeStampToken,          -- according to RFC 3161
+                crl         CertificateList OPTIONAL -- according to RFC 5280
+             }
+            </pre>
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.TimeStampedData.ToAsn1Object">
+            <pre>
+            TimeStampedData ::= SEQUENCE {
+              version              INTEGER { v1(1) },
+              dataUri              IA5String OPTIONAL,
+              metaData             MetaData OPTIONAL,
+              content              OCTET STRING OPTIONAL,
+              temporalEvidence     Evidence
+            }
+            </pre>
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Cms.TimeStampTokenEvidence.ToAsn1Object">
+            <pre>
+            TimeStampTokenEvidence ::=
+               SEQUENCE SIZE(1..MAX) OF TimeStampAndCrl
+            </pre>
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.AttributeTypeAndValue.ToAsn1Object">
+            <pre>
+            AttributeTypeAndValue ::= SEQUENCE {
+                      type         OBJECT IDENTIFIER,
+                      value        ANY DEFINED BY type }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertId.ToAsn1Object">
+            <pre>
+            CertId ::= SEQUENCE {
+                            issuer           GeneralName,
+                            serialNumber     INTEGER }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertReqMessages.ToAsn1Object">
+            <pre>
+            CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertReqMsg.#ctor(Org.BouncyCastle.Asn1.Crmf.CertRequest,Org.BouncyCastle.Asn1.Crmf.ProofOfPossession,Org.BouncyCastle.Asn1.Crmf.AttributeTypeAndValue[])">
+            Creates a new CertReqMsg.
+            @param certReq CertRequest
+            @param popo may be null
+            @param regInfo may be null
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertReqMsg.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertRequest.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertTemplate.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertTemplateBuilder.SetVersion(System.Int32)">
+            Sets the X.509 version. Note: for X509v3, use 2 here. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertTemplateBuilder.SetIssuerUID(Org.BouncyCastle.Asn1.DerBitString)">
+            Sets the issuer unique ID (deprecated in X.509v3) 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertTemplateBuilder.SetSubjectUID(Org.BouncyCastle.Asn1.DerBitString)">
+            Sets the subject unique ID (deprecated in X.509v3) 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.CertTemplateBuilder.Build">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.Controls.ToAsn1Object">
+            <pre>
+            Controls  ::= SEQUENCE SIZE(1..MAX) OF AttributeTypeAndValue
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.EncKeyWithID.ToAsn1Object">
+            <pre>
+            EncKeyWithID ::= SEQUENCE {
+                 privateKey           PrivateKeyInfo,
+                 identifier CHOICE {
+                    string               UTF8String,
+                    generalName          GeneralName
+                } OPTIONAL
+            }
+            </pre>
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.EncryptedKey.ToAsn1Object">
+            <pre>
+               EncryptedKey ::= CHOICE {
+                   encryptedValue        EncryptedValue, -- deprecated
+                   envelopedData     [0] EnvelopedData }
+                   -- The encrypted private key MUST be placed in the envelopedData
+                   -- encryptedContentInfo encryptedContent OCTET STRING.
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.EncryptedValue.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.OptionalValidity.ToAsn1Object">
+            <pre>
+            OptionalValidity ::= SEQUENCE {
+                                   notBefore  [0] Time OPTIONAL,
+                                   notAfter   [1] Time OPTIONAL } --at least one MUST be present
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PkiArchiveOptions.ToAsn1Object">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PkiPublicationInfo.ToAsn1Object">
+            <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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Crmf.PKMacValue">
+            Password-based MAC value for use with POPOSigningKeyInput.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PKMacValue.#ctor(Org.BouncyCastle.Asn1.Cmp.PbmParameter,Org.BouncyCastle.Asn1.DerBitString)">
+            Creates a new PKMACValue.
+            @param params parameters for password-based MAC
+            @param value MAC of the DER-encoded SubjectPublicKeyInfo
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PKMacValue.#ctor(Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier,Org.BouncyCastle.Asn1.DerBitString)">
+            Creates a new PKMACValue.
+            @param aid CMPObjectIdentifiers.passwordBasedMAC, with PBMParameter
+            @param value MAC of the DER-encoded SubjectPublicKeyInfo
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PKMacValue.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PopoPrivKey.ToAsn1Object">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PopoSigningKey.#ctor(Org.BouncyCastle.Asn1.Crmf.PopoSigningKeyInput,Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier,Org.BouncyCastle.Asn1.DerBitString)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PopoSigningKey.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PopoSigningKeyInput.#ctor(Org.BouncyCastle.Asn1.X509.GeneralName,Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo)">
+            Creates a new PopoSigningKeyInput with sender name as authInfo. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PopoSigningKeyInput.#ctor(Org.BouncyCastle.Asn1.Crmf.PKMacValue,Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo)">
+            Creates a new PopoSigningKeyInput using password-based MAC. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.PopoSigningKeyInput.ToAsn1Object">
+            <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.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Crmf.PopoSigningKeyInput.Sender">
+            Returns the sender field, or null if authInfo is publicKeyMac 
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Crmf.PopoSigningKeyInput.PublicKeyMac">
+            Returns the publicKeyMac field, or null if authInfo is sender 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.#ctor">
+            Creates a ProofOfPossession with type raVerified. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.#ctor(Org.BouncyCastle.Asn1.Crmf.PopoSigningKey)">
+            Creates a ProofOfPossession for a signing key. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.#ctor(System.Int32,Org.BouncyCastle.Asn1.Crmf.PopoPrivKey)">
+            Creates a ProofOfPossession for key encipherment or agreement.
+            @param type one of TYPE_KEY_ENCIPHERMENT or TYPE_KEY_AGREEMENT
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.ToAsn1Object">
+            <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Crmf.SinglePubInfo.ToAsn1Object">
+            <pre>
+            SinglePubInfo ::= SEQUENCE {
+                   pubMethod    INTEGER {
+                      dontCare    (0),
+                      x500        (1),
+                      web         (2),
+                      ldap        (3) },
+                  pubLocation  GeneralName OPTIONAL }
+            </pre>
+            @return a basic ASN.1 object representation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerInteger.GetInstance(System.Object)">
+             return an integer from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerInteger.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.DerInteger.PositiveValue">
+            in some cases positive values Get crammed into a space,
+            that's not quite big enough...
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.CryptoPro.ECGost3410NamedCurves">
+            table of the available named parameters for GOST 3410-2001.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.CryptoPro.ECGost3410NamedCurves.GetByOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             return the ECDomainParameters object for the given OID, null if it
+             isn't present.
+            
+             @param oid an object identifier representing a named parameters, if present.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.CryptoPro.ECGost3410NamedCurves.GetName(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            return the named curve name represented by the given object identifier.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.CryptoPro.ECGost3410NamedCurves.Names">
+            returns an enumeration containing the name strings for curves
+            contained in this structure.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.CryptoPro.Gost28147Parameters.ToAsn1Object">
+             <pre>
+             Gost28147-89-Parameters ::=
+                           SEQUENCE {
+                                   iv                   Gost28147-89-IV,
+                                   encryptionParamSet   OBJECT IDENTIFIER
+                            }
+            
+               Gost28147-89-IV ::= OCTET STRING (SIZE (8))
+             </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.CryptoPro.Gost3410NamedParameters">
+            table of the available named parameters for GOST 3410-94.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.CryptoPro.Gost3410NamedParameters.GetByOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.CryptoPro.Gost3410NamedParameters.Names">
+            returns an enumeration containing the name strings for parameters
+            contained in this structure.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerBmpString">
+            Der BMPString object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBmpString.GetInstance(System.Object)">
+             return a BMP string from the given object.
+            
+             @param obj the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBmpString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBmpString.#ctor(System.Byte[])">
+            basic constructor - byte encoded string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBmpString.#ctor(System.String)">
+            basic constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBoolean.GetInstance(System.Object)">
+             return a bool from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBoolean.GetInstance(System.Boolean)">
+            return a DerBoolean from the passed in bool.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerBoolean.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             return a Boolean 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerEnumerated.GetInstance(System.Object)">
+             return an integer from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerEnumerated.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             return an Enumerated 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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerExternal">
+            Class representing the DER-type External
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerExternal.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.DerInteger,Org.BouncyCastle.Asn1.Asn1Object,Org.BouncyCastle.Asn1.DerTaggedObject)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerExternal.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.DerInteger,Org.BouncyCastle.Asn1.Asn1Object,System.Int32,Org.BouncyCastle.Asn1.Asn1Object)">
+            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
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.DerExternal.Encoding">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerGeneralizedTime">
+            Generalized time object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerGeneralizedTime.GetInstance(System.Object)">
+             return a generalized time from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerGeneralizedTime.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             return a Generalized Time 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 tagged object cannot
+                           be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerGeneralizedTime.#ctor(System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerGeneralizedTime.#ctor(System.DateTime)">
+            base constructor from a local time object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerGeneralizedTime.GetTime">
+            return the time - always in the form of
+             YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+            <p>
+            Normally in a certificate we would expect "Z" rather than "GMT",
+            however adding the "GMT" means we can just use:
+            <pre>
+                dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+            </pre>
+            To read in the time and Get a date which is compatible with our local
+            time zone.</p>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.DerGeneralizedTime.TimeString">
+            Return the time.
+            @return The time string as it appeared in the encoded object.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerIA5String">
+            Der IA5String object - this is an ascii string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerIA5String.GetInstance(System.Object)">
+             return a IA5 string from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerIA5String.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerIA5String.#ctor(System.Byte[])">
+            basic constructor - with bytes.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerIA5String.#ctor(System.String)">
+            basic constructor - without validation.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerIA5String.#ctor(System.String,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerIA5String.IsIA5String(System.String)">
+             return true if the passed in String can be represented without
+             loss as an IA5String, false otherwise.
+            
+             @return true if in printable set, false otherwise.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerNumericString">
+            Der NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerNumericString.GetInstance(System.Object)">
+             return a Numeric string from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerNumericString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerNumericString.#ctor(System.Byte[])">
+            basic constructor - with bytes.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerNumericString.#ctor(System.String)">
+            basic constructor -  without validation..
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerNumericString.#ctor(System.String,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerNumericString.IsNumericString(System.String)">
+             Return true if the string can be represented as a NumericString ('0'..'9', ' ')
+            
+             @param str string to validate.
+             @return true if numeric, fale otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerObjectIdentifier.GetInstance(System.Object)">
+             return an Oid from the passed in object
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerObjectIdentifier.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             return an object Identifier 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerObjectIdentifier.On(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            Return  true if this oid is an extension of the passed in branch, stem.
+            @param stem the arc or branch that is a possible parent.
+            @return  true if the branch is on the passed in stem, false otherwise.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerPrintableString">
+            Der PrintableString object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerPrintableString.GetInstance(System.Object)">
+             return a printable string from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerPrintableString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerPrintableString.#ctor(System.Byte[])">
+            basic constructor - byte encoded string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerPrintableString.#ctor(System.String)">
+            basic constructor - this does not validate the string
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerPrintableString.#ctor(System.String,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerPrintableString.IsPrintableString(System.String)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerT61String">
+            Der T61String (also the teletex string) - 8-bit characters
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerT61String.GetInstance(System.Object)">
+             return a T61 string from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerT61String.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerT61String.#ctor(System.Byte[])">
+            basic constructor - with bytes.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerT61String.#ctor(System.String)">
+            basic constructor - with string.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerUniversalString">
+            Der UniversalString object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUniversalString.GetInstance(System.Object)">
+             return a Universal string from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUniversalString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUniversalString.#ctor(System.Byte[])">
+            basic constructor - byte encoded string.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerUnknownTag">
+            We insert one of these when we find a tag we don't recognise.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUnknownTag.#ctor(System.Int32,System.Byte[])">
+            @param tag the tag value.
+            @param data the contents octets.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerUtcTime">
+            UTC time object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtcTime.GetInstance(System.Object)">
+             return an UTC Time from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtcTime.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtcTime.#ctor(System.String)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtcTime.#ctor(System.DateTime)">
+            base constructor from a DateTime object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtcTime.ToDateTime">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtcTime.ToAdjustedDateTime">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.DerUtcTime.TimeString">
+            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>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.DerUtcTime.AdjustedTimeString">
+            <summary>
+            Return a time string as an adjusted date with a 4 digit year.
+            This goes in the range of 1950 - 2049.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerUtf8String">
+            Der UTF8String object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtf8String.GetInstance(System.Object)">
+             return an UTF8 string from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtf8String.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtf8String.#ctor(System.Byte[])">
+            basic constructor - byte encoded string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerUtf8String.#ctor(System.String)">
+            basic constructor
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.DerVisibleString">
+            Der VisibleString object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerVisibleString.GetInstance(System.Object)">
+             return a Visible string from the passed in object.
+            
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerVisibleString.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerVisibleString.#ctor(System.Byte[])">
+            basic constructor - byte encoded string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.DerVisibleString.#ctor(System.String)">
+            basic constructor
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CertificateValues">
+            <remarks>
+            RFC 3126: 4.3.1 Certificate Values Attribute Definition
+            <code>
+            CertificateValues ::= SEQUENCE OF Certificate
+            </code>
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.CommitmentTypeIndication.ToAsn1Object">
+            <pre>
+            CommitmentTypeIndication ::= SEQUENCE {
+                 commitmentTypeId   CommitmentTypeIdentifier,
+                 commitmentTypeQualifier   SEQUENCE SIZE (1..MAX) OF
+                         CommitmentTypeQualifier OPTIONAL }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CommitmentTypeQualifier">
+             Commitment type qualifiers, used in the Commitment-Type-Indication attribute (RFC3126).
+            
+             <pre>
+               CommitmentTypeQualifier ::= SEQUENCE {
+                   commitmentTypeIdentifier  CommitmentTypeIdentifier,
+                   qualifier          ANY DEFINED BY commitmentTypeIdentifier OPTIONAL }
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.CommitmentTypeQualifier.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             Creates a new <code>CommitmentTypeQualifier</code> instance.
+            
+             @param commitmentTypeIdentifier a <code>CommitmentTypeIdentifier</code> value
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.CommitmentTypeQualifier.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.Asn1Encodable)">
+             Creates a new <code>CommitmentTypeQualifier</code> instance.
+            
+             @param commitmentTypeIdentifier a <code>CommitmentTypeIdentifier</code> value
+             @param qualifier the qualifier, defined by the above field.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.CommitmentTypeQualifier.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Creates a new <code>CommitmentTypeQualifier</code> instance.
+            
+             @param as <code>CommitmentTypeQualifier</code> structure
+             encoded as an Asn1Sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.CommitmentTypeQualifier.ToAsn1Object">
+             Returns a DER-encodable representation of this instance.
+            
+             @return a <code>Asn1Object</code> value
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CompleteCertificateRefs">
+            <remarks>
+            RFC 3126: 4.2.1 Complete Certificate Refs Attribute Definition
+            <code>
+            CompleteCertificateRefs ::= SEQUENCE OF OtherCertID
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CompleteRevocationRefs">
+            <remarks>
+            RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+            <code>
+            CompleteRevocationRefs ::= SEQUENCE OF CrlOcspRef
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CrlIdentifier">
+            <remarks>
+            RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+            <code>
+            CrlIdentifier ::= SEQUENCE 
+            {
+            	crlissuer		Name,
+            	crlIssuedTime	UTCTime,
+            	crlNumber		INTEGER OPTIONAL
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CrlListID">
+            <remarks>
+            RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+            <code>
+            CRLListID ::= SEQUENCE 
+            {
+            	crls	SEQUENCE OF CrlValidatedID
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CrlOcspRef">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.CrlValidatedID">
+            <remarks>
+            RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+            <code>
+            CrlValidatedID ::= SEQUENCE {
+            	crlHash			OtherHash,
+            	crlIdentifier	CrlIdentifier OPTIONAL}
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OcspIdentifier">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OcspListID">
+            <remarks>
+            RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+            <code>
+            OcspListID ::=  SEQUENCE {
+            	ocspResponses	SEQUENCE OF OcspResponsesID
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OcspResponsesID">
+            <remarks>
+            RFC 3126: 4.2.2 Complete Revocation Refs Attribute Definition
+            <code>
+            OcspResponsesID ::= SEQUENCE {
+            	ocspIdentifier	OcspIdentifier,
+            	ocspRepHash		OtherHash OPTIONAL
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OtherCertID">
+            <remarks>
+            <code>
+            OtherCertID ::= SEQUENCE {
+            	otherCertHash	OtherHash,
+            	issuerSerial	IssuerSerial OPTIONAL
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OtherHash">
+            <remarks>
+            <code>
+            OtherHash ::= CHOICE {
+            	sha1Hash	OtherHashValue, -- This contains a SHA-1 hash
+            	otherHash	OtherHashAlgAndValue
+            }
+            
+            OtherHashValue ::= OCTET STRING
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OtherHashAlgAndValue">
+            <summary>
+            Summary description for OtherHashAlgAndValue.
+            </summary>
+            <remarks>
+            <code>
+            OtherHashAlgAndValue ::= SEQUENCE {
+            	hashAlgorithm	AlgorithmIdentifier,
+            	hashValue		OtherHashValue
+            }
+            
+            OtherHashValue ::= OCTET STRING
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OtherRevRefs">
+             <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OtherRevVals">
+             <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.OtherSigningCertificate">
+            <remarks>
+            <code>
+            OtherSigningCertificate ::= SEQUENCE {
+            	certs		SEQUENCE OF OtherCertID,
+            	policies	SEQUENCE OF PolicyInformation OPTIONAL
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.RevocationValues">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.SignaturePolicyId">
+            <remarks>
+            <code>
+            SignaturePolicyId ::= SEQUENCE {
+            	sigPolicyIdentifier		SigPolicyId,
+            	sigPolicyHash			SigPolicyHash,
+            	sigPolicyQualifiers		SEQUENCE SIZE (1..MAX) OF SigPolicyQualifierInfo OPTIONAL
+            }
+            
+            SigPolicyId ::= OBJECT IDENTIFIER
+            
+            SigPolicyHash ::= OtherHashAlgAndValue
+            </code>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.SignaturePolicyIdentifier">
+            <remarks>
+            <code>
+            SignaturePolicyIdentifier ::= CHOICE {
+            	SignaturePolicyId		SignaturePolicyId,
+            	SignaturePolicyImplied	SignaturePolicyImplied
+            }
+            
+            SignaturePolicyImplied ::= NULL
+            </code>
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.SignerAttribute.ToAsn1Object">
+            
+             <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.SignerLocation">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Esf.SignerLocation.ToAsn1Object">
+             <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Esf.SigPolicyQualifierInfo">
+            <remarks>
+            <code>
+            SigPolicyQualifierInfo ::= SEQUENCE {
+            	sigPolicyQualifierId  SigPolicyQualifierId,
+            	sigQualifier          ANY DEFINED BY sigPolicyQualifierId
+            }
+            
+            SigPolicyQualifierId ::= OBJECT IDENTIFIER
+            </code>
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.ContentHints.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.ContentHints.ToAsn1Object">
+            <pre>
+            ContentHints ::= SEQUENCE {
+              contentDescription UTF8String (SIZE (1..MAX)) OPTIONAL,
+              contentType ContentType }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.ContentIdentifier.#ctor(Org.BouncyCastle.Asn1.Asn1OctetString)">
+            Create from OCTET STRING whose octets represent the identifier.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.ContentIdentifier.#ctor(System.Byte[])">
+            Create from byte array representing the identifier.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.ContentIdentifier.ToAsn1Object">
+            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 }
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.EssCertID.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.EssCertID.ToAsn1Object">
+            <pre>
+            EssCertID ::= SEQUENCE {
+                certHash Hash,
+                issuerSerial IssuerSerial OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.EssCertIDv2.ToAsn1Object">
+             <pre>
+             EssCertIDv2 ::=  SEQUENCE {
+                 hashAlgorithm     AlgorithmIdentifier
+                          DEFAULT {algorithm id-sha256},
+                 certHash          Hash,
+                 issuerSerial      IssuerSerial OPTIONAL
+             }
+            
+             Hash ::= OCTET STRING
+            
+             IssuerSerial ::= SEQUENCE {
+                 issuer         GeneralNames,
+                 serialNumber   CertificateSerialNumber
+             }
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.OtherCertID.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.OtherCertID.ToAsn1Object">
+             <pre>
+             OtherCertID ::= SEQUENCE {
+                 otherCertHash    OtherHash,
+                 issuerSerial     IssuerSerial OPTIONAL }
+            
+             OtherHash ::= CHOICE {
+                 sha1Hash     OCTET STRING,
+                 otherHash    OtherHashAlgAndValue }
+            
+             OtherHashAlgAndValue ::= SEQUENCE {
+                 hashAlgorithm    AlgorithmIdentifier,
+                 hashValue        OCTET STRING }
+            
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.OtherSigningCertificate.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            constructors
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.OtherSigningCertificate.ToAsn1Object">
+            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 }
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.SigningCertificate.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            constructors
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.SigningCertificate.ToAsn1Object">
+            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 }
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ess.SigningCertificateV2.ToAsn1Object">
+            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 }
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Icao.CscaMasterList">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Icao.DataGroupHash">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Icao.LdsSecurityObject">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Icao.LdsVersionInfo.ToAsn1Object">
+            <pre>
+            LDSVersionInfo ::= SEQUENCE {
+               ldsVersion PRINTABLE STRING
+               unicodeVersion PRINTABLE STRING
+             }
+            </pre>
+            @return
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttCPAccredited">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATDateOfCertGen">
+             Certificate extensionDate of certificate generation
+             
+             <pre>
+            		DateOfCertGenSyntax ::= GeneralizedTime
+             </pre>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATProcuration">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATAdmission">
+            Attribute to indicate admissions to certain professions. May be used as
+            attribute in attribute certificate or as extension in a certificate
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATMonetaryLimit">
+            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).
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATDeclarationOfMajority">
+            A declaration of majority. May be used as attribute in attribute
+            certificate or as extension in a certificate
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATIccsn">
+             
+             Serial number of the smart card containing the corresponding private key
+             
+             <pre>
+            		ICCSNSyntax ::= OCTET STRING (SIZE(8..20))
+             </pre>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATPKReference">
+             
+             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>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATRestriction">
+             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
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATRetrieveIfAllowed">
+             
+             (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>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATRequestedCertificate">
+            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
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATNamingAuthorities">
+            Base ObjectIdentifier for naming authorities
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATCertInDirSince">
+             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>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATCertHash">
+             Hash of a certificate in OCSP.
+            
+             @see Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATNameAtBirth">
+             <pre>
+            		NameAtBirth ::= DirectoryString(SIZE(1..64)
+             </pre>
+             
+             Used in
+             {@link Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes SubjectDirectoryAttributes}
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATAdditionalInformation">
+            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
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.IsisMttObjectIdentifiers.IdIsisMttATLiabilityLimitationFlag">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash.#ctor(Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier,System.Byte[])">
+             Constructor from a given details.
+            
+             @param hashAlgorithm   The hash algorithm identifier.
+             @param certificateHash The hash of the whole DER encoding of the certificate.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.CertHash.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <p/>
+             Returns:
+             <p/>
+             <pre>
+                 CertHash ::= SEQUENCE {
+                   hashAlgorithm AlgorithmIdentifier,
+                   certificateHash OCTET STRING
+                 }
+             </pre>
+            
+             @return an Asn1Object
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.RequestedCertificate">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.RequestedCertificate.#ctor(Org.BouncyCastle.Asn1.X509.X509CertificateStructure)">
+             Constructor from a given details.
+             <p/>
+             Only one parameter can be given. All other must be <code>null</code>.
+            
+             @param certificate Given as Certificate
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.Ocsp.RequestedCertificate.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.AdditionalInformationSyntax">
+            Some other information of non-restrictive nature regarding the usage of this
+            certificate.
+            
+            <pre>
+               AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.AdditionalInformationSyntax.#ctor(System.String)">
+             Constructor from a given details.
+            
+             @param information The describtion of the information.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.AdditionalInformationSyntax.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <p/>
+             Returns:
+             <p/>
+             <pre>
+               AdditionalInformationSyntax ::= DirectoryString (SIZE(1..2048))
+             </pre>
+            
+             @return an Asn1Object
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.Admissions">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.Admissions.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.Admissions.#ctor(Org.BouncyCastle.Asn1.X509.GeneralName,Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority,Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.Admissions.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax">
+             Attribute to indicate admissions to certain professions.
+             <p/>
+             <pre>
+                 AdmissionSyntax ::= SEQUENCE
+                 {
+                   admissionAuthority GeneralName OPTIONAL,
+                   contentsOfAdmissions SEQUENCE OF Admissions
+                 }
+             <p/>
+                 Admissions ::= SEQUENCE
+                 {
+                   admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+                   namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+                   professionInfos SEQUENCE OF ProfessionInfo
+                 }
+             <p/>
+                 NamingAuthority ::= SEQUENCE
+                 {
+                   namingAuthorityId OBJECT IDENTIFIER OPTIONAL,
+                   namingAuthorityUrl IA5String OPTIONAL,
+                   namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+                 }
+             <p/>
+                 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>
+             <p/>
+             <p/>
+             ISIS-MTT PROFILE: The relatively complex structure of AdmissionSyntax
+             supports the following concepts and requirements:
+             <ul>
+             <li> External institutions (e.g. professional associations, chambers, unions,
+             administrative bodies, companies, etc.), which are responsible for granting
+             and verifying professional admissions, are indicated by means of the data
+             field admissionAuthority. An admission authority is indicated by a
+             GeneralName object. Here an X.501 directory name (distinguished name) can be
+             indicated in the field directoryName, a URL address can be indicated in the
+             field uniformResourceIdentifier, and an object identifier can be indicated in
+             the field registeredId.</li>
+             <li> The names of authorities which are responsible for the administration of
+             title registers are indicated in the data field namingAuthority. The name of
+             the authority can be identified by an object identifier in the field
+             namingAuthorityId, by means of a text string in the field
+             namingAuthorityText, by means of a URL address in the field
+             namingAuthorityUrl, or by a combination of them. For example, the text string
+             can contain the name of the authority, the country and the name of the title
+             register. The URL-option refers to a web page which contains lists with
+             �officially� registered professions (text and possibly OID) as well as
+             further information on these professions. Object identifiers for the
+             component namingAuthorityId are grouped under the OID-branch
+             id-isis-at-namingAuthorities and must be applied for.</li>
+             <li>See http://www.teletrust.de/anwend.asp?Id=30200&amp;Sprache=E_&amp;HomePG=0
+             for an application form and http://www.teletrust.de/links.asp?id=30220,11
+             for an overview of registered naming authorities.</li>
+             <li> By means of the data type ProfessionInfo certain professions,
+             specializations, disciplines, fields of activity, etc. are identified. A
+             profession is represented by one or more text strings, resp. profession OIDs
+             in the fields professionItems and professionOIDs and by a registration number
+             in the field registrationNumber. An indication in text form must always be
+             present, whereas the other indications are optional. The component
+             addProfessionInfo may contain additional applicationspecific information in
+             DER-encoded form.</li>
+             </ul>
+             <p/>
+             By means of different namingAuthority-OIDs or profession OIDs hierarchies of
+             professions, specializations, disciplines, fields of activity, etc. can be
+             expressed. The issuing admission authority should always be indicated (field
+             admissionAuthority), whenever a registration number is presented. Still,
+             information on admissions can be given without indicating an admission or a
+             naming authority by the exclusive use of the component professionItems. In
+             this case the certification authority is responsible for the verification of
+             the admission information.
+             <p/>
+             <p/>
+             <p/>
+             This attribute is single-valued. Still, several admissions can be captured in
+             the sequence structure of the component contentsOfAdmissions of
+             AdmissionSyntax or in the component professionInfos of Admissions. The
+             component admissionAuthority of AdmissionSyntax serves as default value for
+             the component admissionAuthority of Admissions. Within the latter component
+             the default value can be overwritten, in case that another authority is
+             responsible. The component namingAuthority of Admissions serves as a default
+             value for the component namingAuthority of ProfessionInfo. Within the latter
+             component the default value can be overwritten, in case that another naming
+             authority needs to be recorded.
+             <p/>
+             The length of the string objects is limited to 128 characters. It is
+             recommended to indicate a namingAuthorityURL in all issued attribute
+             certificates. If a namingAuthorityURL is indicated, the field professionItems
+             of ProfessionInfo should contain only registered titles. If the field
+             professionOIDs exists, it has to contain the OIDs of the professions listed
+             in professionItems in the same order. In general, the field professionInfos
+             should contain only one entry, unless the admissions that are to be listed
+             are logically connected (e.g. they have been issued under the same admission
+             number).
+            
+             @see Org.BouncyCastle.Asn1.IsisMtt.X509.Admissions
+             @see Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo
+             @see Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Constructor from Asn1Sequence.
+             <p/>
+             The sequence is of type ProcurationSyntax:
+             <p/>
+             <pre>
+                 AdmissionSyntax ::= SEQUENCE
+                 {
+                   admissionAuthority GeneralName OPTIONAL,
+                   contentsOfAdmissions SEQUENCE OF Admissions
+                 }
+             <p/>
+                 Admissions ::= SEQUENCE
+                 {
+                   admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+                   namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+                   professionInfos SEQUENCE OF ProfessionInfo
+                 }
+             <p/>
+                 NamingAuthority ::= SEQUENCE
+                 {
+                   namingAuthorityId OBJECT IDENTIFIER OPTIONAL,
+                   namingAuthorityUrl IA5String OPTIONAL,
+                   namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+                 }
+             <p/>
+                 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax.#ctor(Org.BouncyCastle.Asn1.X509.GeneralName,Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Constructor from given details.
+            
+             @param admissionAuthority   The admission authority.
+             @param contentsOfAdmissions The admissions.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <p/>
+             Returns:
+             <p/>
+             <pre>
+                 AdmissionSyntax ::= SEQUENCE
+                 {
+                   admissionAuthority GeneralName OPTIONAL,
+                   contentsOfAdmissions SEQUENCE OF Admissions
+                 }
+             <p/>
+                 Admissions ::= SEQUENCE
+                 {
+                   admissionAuthority [0] EXPLICIT GeneralName OPTIONAL
+                   namingAuthority [1] EXPLICIT NamingAuthority OPTIONAL
+                   professionInfos SEQUENCE OF ProfessionInfo
+                 }
+             <p/>
+                 NamingAuthority ::= SEQUENCE
+                 {
+                   namingAuthorityId OBJECT IDENTIFIER OPTIONAL,
+                   namingAuthorityUrl IA5String OPTIONAL,
+                   namingAuthorityText DirectoryString(SIZE(1..128)) OPTIONAL
+                 }
+             <p/>
+                 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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax.GetContentsOfAdmissions">
+            @return Returns the contentsOfAdmissions.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.AdmissionSyntax.AdmissionAuthority">
+            @return Returns the admissionAuthority if present, null otherwise.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.DeclarationOfMajority">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.DeclarationOfMajority.ToAsn1Object">
+             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
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.DeclarationOfMajority.NotYoungerThan">
+            @return notYoungerThan if that's what we are, -1 otherwise
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.MonetaryLimit">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.MonetaryLimit.#ctor(System.String,System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.MonetaryLimit.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority">
+            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
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.IdIsisMttATNamingAuthoritiesRechtWirtschaftSteuern">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.String,Org.BouncyCastle.Asn1.X500.DirectoryString)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.ToAsn1Object">
+             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
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.NamingAuthorityID">
+            @return Returns the namingAuthorityID.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.NamingAuthorityText">
+            @return Returns the namingAuthorityText.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority.NamingAuthorityUrl">
+            @return Returns the namingAuthorityUrl.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.ProcurationSyntax">
+            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>
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProcurationSyntax.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProcurationSyntax.#ctor(System.String,Org.BouncyCastle.Asn1.X500.DirectoryString,Org.BouncyCastle.Asn1.X509.IssuerSerial)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProcurationSyntax.#ctor(System.String,Org.BouncyCastle.Asn1.X500.DirectoryString,Org.BouncyCastle.Asn1.X509.GeneralName)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProcurationSyntax.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo">
+            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
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Rechtsanwltin">
+            Rechtsanw�ltin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Rechtsanwalt">
+            Rechtsanwalt
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Rechtsbeistand">
+            Rechtsbeistand
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Steuerberaterin">
+            Steuerberaterin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Steuerberater">
+            Steuerberater
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Steuerbevollmchtigte">
+            Steuerbevollm�chtigte
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Steuerbevollmchtigter">
+            Steuerbevollm�chtigter
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Notarin">
+            Notarin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Notar">
+            Notar
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Notarvertreterin">
+            Notarvertreterin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Notarvertreter">
+            Notarvertreter
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Notariatsverwalterin">
+            Notariatsverwalterin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Notariatsverwalter">
+            Notariatsverwalter
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Wirtschaftsprferin">
+            Wirtschaftspr�ferin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Wirtschaftsprfer">
+            Wirtschaftspr�fer
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.VereidigteBuchprferin">
+            Vereidigte Buchpr�ferin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.VereidigterBuchprfer">
+            Vereidigter Buchpr�fer
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Patentanwltin">
+            Patentanw�ltin
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.Patentanwalt">
+            Patentanwalt
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.#ctor(Org.BouncyCastle.Asn1.IsisMtt.X509.NamingAuthority,Org.BouncyCastle.Asn1.X500.DirectoryString[],Org.BouncyCastle.Asn1.DerObjectIdentifier[],System.String,Org.BouncyCastle.Asn1.Asn1OctetString)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.ToAsn1Object">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.GetProfessionItems">
+            @return Returns the professionItems.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.GetProfessionOids">
+            @return Returns the professionOids.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.AddProfessionInfo">
+            @return Returns the addProfessionInfo.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.NamingAuthority">
+            @return Returns the namingAuthority.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.IsisMtt.X509.ProfessionInfo.RegistrationNumber">
+            @return Returns the registrationNumber.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.IsisMtt.X509.Restriction">
+            Some other restriction regarding the usage of this certificate.
+            <p/>
+            <pre>
+             RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.Restriction.#ctor(Org.BouncyCastle.Asn1.X500.DirectoryString)">
+             Constructor from DirectoryString.
+             <p/>
+             The DirectoryString is of type RestrictionSyntax:
+             <p/>
+             <pre>
+                  RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+             </pre>
+            
+             @param restriction A IAsn1String.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.Restriction.#ctor(System.String)">
+             Constructor from a given details.
+            
+             @param restriction The description of the restriction.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.IsisMtt.X509.Restriction.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+             <p/>
+             Returns:
+             <p/>
+             <pre>
+                  RestrictionSyntax ::= DirectoryString (SIZE(1..1024))
+             <p/>
+             </pre>
+            
+             @return an Asn1Object
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Misc.Cast5CbcParameters.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            cast5CBCParameters ::= Sequence {
+                                      iv         OCTET STRING DEFAULT 0,
+                                             -- Initialization vector
+                                      keyLength  Integer
+                                             -- Key length, in bits
+                                 }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Misc.IdeaCbcPar.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            IDEA-CBCPar ::= Sequence {
+                                 iv    OCTET STRING OPTIONAL -- exactly 8 octets
+                             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Misc.NetscapeCertType">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Misc.NetscapeCertType.#ctor(System.Int32)">
+             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)
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Mozilla.PublicKeyAndChallenge">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Nist.NistNamedCurves">
+            Utility class for fetching curves using their NIST names as published in FIPS-PUB 186-2
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Nist.NistNamedCurves.GetByOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Nist.NistNamedCurves.GetOid(System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Nist.NistNamedCurves.GetName(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            return the named curve name represented by the given object identifier.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Nist.NistNamedCurves.Names">
+            returns an enumeration containing the name strings for curves
+            contained in this structure.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Ntt.NttObjectIdentifiers">
+            <summary>From RFC 3657</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.BasicOcspResponse.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.CertID.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.CertStatus.#ctor">
+            create a CertStatus object with a tag of zero.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.CertStatus.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             CertStatus ::= CHOICE {
+                             good        [0]     IMPLICIT Null,
+                             revoked     [1]     IMPLICIT RevokedInfo,
+                             unknown     [2]     IMPLICIT UnknownInfo }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.CrlID.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.OcspRequest.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            OcspRequest     ::=     Sequence {
+                tbsRequest                  TBSRequest,
+                optionalSignature   [0]     EXPLICIT Signature OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.OcspResponse.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            OcspResponse ::= Sequence {
+                responseStatus         OcspResponseStatus,
+                responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.OcspResponseStatus.#ctor(System.Int32)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.Request.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Request         ::=     Sequence {
+                reqCert                     CertID,
+                singleRequestExtensions     [0] EXPLICIT Extensions OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.ResponderID.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            ResponderID ::= CHOICE {
+                 byName          [1] Name,
+                 byKey           [2] KeyHash }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.ResponseBytes.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            ResponseBytes ::=       Sequence {
+                responseType   OBJECT IDENTIFIER,
+                response       OCTET STRING }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.ResponseData.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.RevokedInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            RevokedInfo ::= Sequence {
+                 revocationTime              GeneralizedTime,
+                 revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.ServiceLocator.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            ServiceLocator ::= Sequence {
+                issuer    Name,
+                locator   AuthorityInfoAccessSyntax OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.Signature.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Signature       ::=     Sequence {
+                signatureAlgorithm      AlgorithmIdentifier,
+                signature               BIT STRING,
+                certs               [0] EXPLICIT Sequence OF Certificate OPTIONAL}
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.SingleResponse.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Ocsp.TbsRequest.ToAsn1Object">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.OidTokenizer">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.AttributePkcs.GetInstance(System.Object)">
+             return an Attribute object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.AttributePkcs.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Attr ::= Sequence {
+                attrType OBJECT IDENTIFIER,
+                attrValues Set OF AttributeValue
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Pkcs.CertificationRequest">
+            Pkcs10 Certfication request object.
+            <pre>
+            CertificationRequest ::= Sequence {
+              certificationRequestInfo  CertificationRequestInfo,
+              signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+              signature                 BIT STRING
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Pkcs.CertificationRequestInfo">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.ContentInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            ContentInfo ::= Sequence {
+                     contentType ContentType,
+                     content
+                     [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Pkcs.EncryptedData">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.EncryptedPrivateKeyInfo.ToAsn1Object">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+                 AlgorithmIdentifier ::= Sequence {
+                                       algorithm OBJECT IDENTIFIER,
+                                       parameters ANY DEFINED BY algorithm OPTIONAL }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.MacData.ToAsn1Object">
+            <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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Pkcs.Pfx">
+            the infamous Pfx from Pkcs12
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.PrivateKeyInfo.ToAsn1Object">
+             write out an RSA private key with its associated information
+             as described in Pkcs8.
+             <pre>
+                  PrivateKeyInfo ::= Sequence {
+                                          version Version,
+                                          privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
+                                          privateKey PrivateKey,
+                                          attributes [0] IMPLICIT Attributes OPTIONAL
+                                      }
+                  Version ::= Integer {v1(0)} (v1,...)
+            
+                  PrivateKey ::= OCTET STRING
+            
+                  Attributes ::= Set OF Attr
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.RsaesOaepParameters.#ctor">
+            The default version
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.RsaesOaepParameters.ToAsn1Object">
+             <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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.RsaPrivateKeyStructure.ToAsn1Object">
+             This outputs the key in Pkcs1v2 format.
+             <pre>
+                  RsaPrivateKey ::= Sequence {
+                                      version Version,
+                                      modulus Integer, -- n
+                                      publicExponent Integer, -- e
+                                      privateExponent Integer, -- d
+                                      prime1 Integer, -- p
+                                      prime2 Integer, -- q
+                                      exponent1 Integer, -- d mod (p-1)
+                                      exponent2 Integer, -- d mod (q-1)
+                                      coefficient Integer -- (inverse of q) mod p
+                                  }
+            
+                  Version ::= Integer
+             </pre>
+             <p>This routine is written to output Pkcs1 version 0, private keys.</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.RsassaPssParameters.#ctor">
+            The default version
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.RsassaPssParameters.ToAsn1Object">
+             <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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Pkcs.SignedData">
+            a Pkcs#7 signed data object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.SignedData.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             SignedData ::= Sequence {
+                 version Version,
+                 digestAlgorithms DigestAlgorithmIdentifiers,
+                 contentInfo ContentInfo,
+                 certificates
+                     [0] IMPLICIT ExtendedCertificatesAndCertificates
+                              OPTIONAL,
+                 crls
+                     [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+                 signerInfos SignerInfos }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Pkcs.SignerInfo">
+            a Pkcs#7 signer info object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Pkcs.SignerInfo.ToAsn1Object">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Sec.ECPrivateKeyStructure">
+            the elliptic curve private key object from SEC 1
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Sec.ECPrivateKeyStructure.ToAsn1Object">
+            ECPrivateKey ::= SEQUENCE {
+                version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+                privateKey OCTET STRING,
+                parameters [0] Parameters OPTIONAL,
+                publicKey [1] BIT STRING OPTIONAL }
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetOid(System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetName(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            return the named curve name represented by the given object identifier.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.Sec.SecNamedCurves.Names">
+            returns an enumeration containing the name strings for curves
+            contained in this structure.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.Sec.SecObjectIdentifiers.EllipticCurve">
+            EllipticCurve OBJECT IDENTIFIER ::= {
+                  iso(1) identified-organization(3) certicom(132) curve(0)
+            }
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Smime.SmimeCapabilities">
+            Handler class for dealing with S/MIME Capabilities
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.Smime.SmimeCapabilities.PreferSignedData">
+            general preferences
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.Smime.SmimeCapabilities.DesCbc">
+            encryption algorithms preferences
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Smime.SmimeCapabilities.GetInstance(System.Object)">
+             return an Attr object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Smime.SmimeCapabilities.GetCapabilitiesForOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            returns an ArrayList with 0 or more objects of all the capabilities
+            matching the passed in capability Oid. If the Oid passed is null the
+            entire set is returned.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Smime.SmimeCapabilities.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            SMIMECapabilities ::= Sequence OF SMIMECapability
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttributeX509.GetInstance(System.Object)">
+             return an Attr object from the given object.
+            
+             @param o the object we want converted.
+             @exception ArgumentException if the object cannot be converted.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttributeX509.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Attr ::= Sequence {
+                attrType OBJECT IDENTIFIER,
+                attrValues Set OF AttributeValue
+            }
+            </pre>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.Smime.SmimeCapability.PreferSignedData">
+            general preferences
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.Smime.SmimeCapability.DesCbc">
+            encryption algorithms preferences
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Smime.SmimeCapability.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            SMIMECapability ::= Sequence {
+                capabilityID OBJECT IDENTIFIER,
+                parameters ANY DEFINED BY capabilityID OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Smime.SmimeCapabilityVector">
+            Handler for creating a vector S/MIME Capabilities
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.Smime.SmimeEncryptionKeyPreferenceAttribute">
+            The SmimeEncryptionKeyPreference object.
+            <pre>
+            SmimeEncryptionKeyPreference ::= CHOICE {
+                issuerAndSerialNumber   [0] IssuerAndSerialNumber,
+                receipentKeyId          [1] RecipientKeyIdentifier,
+                subjectAltKeyIdentifier [2] SubjectKeyIdentifier
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Smime.SmimeEncryptionKeyPreferenceAttribute.#ctor(Org.BouncyCastle.Asn1.Asn1OctetString)">
+            @param sKeyId the subjectKeyIdentifier value (normally the X.509 one)
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.TeleTrust.TeleTrusTNamedCurves">
+            elliptic curves defined in "ECC Brainpool Standard Curves and Curve Generation"
+            http://www.ecc-brainpool.org/download/draft_pkix_additional_ecc_dp.txt
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.TeleTrust.TeleTrusTNamedCurves.GetByOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.TeleTrust.TeleTrusTNamedCurves.GetOid(System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.TeleTrust.TeleTrusTNamedCurves.GetName(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            return the named curve name represented by the given object identifier.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.TeleTrust.TeleTrusTNamedCurves.Names">
+            returns an enumeration containing the name strings for curves
+            contained in this structure.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Tsp.Accuracy.ToAsn1Object">
+            <pre>
+            Accuracy ::= SEQUENCE {
+                        seconds        INTEGER              OPTIONAL,
+                        millis     [0] INTEGER  (1..999)    OPTIONAL,
+                        micros     [1] INTEGER  (1..999)    OPTIONAL
+                        }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Tsp.MessageImprint.GetInstance(System.Object)">
+            @param o
+            @return a MessageImprint object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Tsp.MessageImprint.ToAsn1Object">
+            <pre>
+               MessageImprint ::= SEQUENCE  {
+                  hashAlgorithm                AlgorithmIdentifier,
+                  hashedMessage                OCTET STRING  }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Tsp.TimeStampReq.ToAsn1Object">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Tsp.TimeStampResp.ToAsn1Object">
+            <pre>
+            TimeStampResp ::= SEQUENCE  {
+              status                  PkiStatusInfo,
+              timeStampToken          TimeStampToken     OPTIONAL  }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Tsp.TstInfo.ToAsn1Object">
+             <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Utilities.Asn1Dump.AsString(System.String,System.Boolean,Org.BouncyCastle.Asn1.Asn1Object,System.Text.StringBuilder)">
+             dump a Der object as a formatted string with indentation
+            
+             @param obj the Asn1Object to be dumped out.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Utilities.Asn1Dump.DumpAsString(Org.BouncyCastle.Asn1.Asn1Encodable)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.Utilities.Asn1Dump.DumpAsString(Org.BouncyCastle.Asn1.Asn1Encodable,System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X500.DirectoryString.ToAsn1Object">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.AccessDescription">
+            The AccessDescription object.
+            <pre>
+            AccessDescription  ::=  SEQUENCE {
+                  accessMethod          OBJECT IDENTIFIER,
+                  accessLocation        GeneralName  }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AccessDescription.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.X509.GeneralName)">
+            create an AccessDescription with the oid and location provided.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.AccessDescription.AccessMethod">
+            
+             @return the access method.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.AccessDescription.AccessLocation">
+            
+             @return the access location
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttCertIssuer.#ctor(Org.BouncyCastle.Asn1.X509.GeneralNames)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttCertIssuer.ToAsn1Object">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttCertValidityPeriod.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             AttCertValidityPeriod  ::= Sequence {
+                  notBeforeTime  GeneralizedTime,
+                  notAfterTime   GeneralizedTime
+             }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttributeCertificate.GetInstance(System.Object)">
+            @param obj
+            @return
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttributeCertificate.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             AttributeCertificate ::= Sequence {
+                  acinfo               AttributeCertificateInfo,
+                  signatureAlgorithm   AlgorithmIdentifier,
+                  signatureValue       BIT STRING
+             }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AttributeCertificateInfo.ToAsn1Object">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.AuthorityInformationAccess">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityInformationAccess.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.X509.GeneralName)">
+            create an AuthorityInformationAccess with the oid and location provided.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier">
+             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>
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier.#ctor(Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo)">
+                     *
+                     * 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>
+                     *
+                     *
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier.#ctor(Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo,Org.BouncyCastle.Asn1.X509.GeneralNames,Org.BouncyCastle.Math.BigInteger)">
+            create an AuthorityKeyIdentifier with the GeneralNames tag and
+            the serial number provided as well.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier.#ctor(Org.BouncyCastle.Asn1.X509.GeneralNames,Org.BouncyCastle.Math.BigInteger)">
+            create an AuthorityKeyIdentifier with the GeneralNames tag and
+            the serial number provided.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier.#ctor(System.Byte[])">
+            create an AuthorityKeyIdentifier with a precomputed key identifier
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier.#ctor(System.Byte[],Org.BouncyCastle.Asn1.X509.GeneralNames,Org.BouncyCastle.Math.BigInteger)">
+            create an AuthorityKeyIdentifier with a precomupted key identifier
+            and the GeneralNames tag and the serial number provided as well.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.BasicConstraints.#ctor(System.Int32)">
+             create a cA=true object for the given path length constraint.
+            
+             @param pathLenConstraint
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.BasicConstraints.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            BasicConstraints := Sequence {
+               cA                  Boolean DEFAULT FALSE,
+               pathLenConstraint   Integer (0..MAX) OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.CertificateList">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.CertificatePair">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.CertificatePair.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.CertificatePair.#ctor(Org.BouncyCastle.Asn1.X509.X509CertificateStructure,Org.BouncyCastle.Asn1.X509.X509CertificateStructure)">
+             Constructor from a given details.
+            
+             @param forward Certificates issued to this CA.
+             @param reverse Certificates issued by this CA to other CAs.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.CertificatePair.ToAsn1Object">
+             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
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.CertificatePair.Forward">
+            @return Returns the forward.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.CertificatePair.Reverse">
+            @return Returns the reverse.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.CertPolicyID">
+             CertPolicyId, used in the CertificatePolicies and PolicyMappings
+             X509V3 Extensions.
+            
+             <pre>
+                 CertPolicyId ::= OBJECT IDENTIFIER
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.CrlDistPoint.GetDistributionPoints">
+             Return the distribution points making up the sequence.
+            
+             @return DistributionPoint[]
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.CrlDistPoint.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            CrlDistPoint ::= Sequence SIZE {1..MAX} OF DistributionPoint
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.CrlNumber">
+            The CRLNumber object.
+            <pre>
+            CRLNumber::= Integer(0..MAX)
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.CrlReason">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.DigestInfo">
+            The DigestInfo object.
+            <pre>
+            DigestInfo::=Sequence{
+                     digestAlgorithm  AlgorithmIdentifier,
+                     digest OCTET STRING }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.DisplayText">
+             <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
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.DisplayText.ContentTypeIA5String">
+             Constant corresponding to ia5String encoding.
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.DisplayText.ContentTypeBmpString">
+             Constant corresponding to bmpString encoding.
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.DisplayText.ContentTypeUtf8String">
+             Constant corresponding to utf8String encoding.
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.DisplayText.ContentTypeVisibleString">
+             Constant corresponding to visibleString encoding.
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.DisplayText.DisplayTextMaximumSize">
+             Describe constant <code>DisplayTextMaximumSize</code> here.
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.DisplayText.#ctor(System.Int32,System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.DisplayText.#ctor(System.String)">
+             Creates a new <code>DisplayText</code> instance.
+            
+             @param text the text to encapsulate. Strings longer than 200
+             characters are truncated.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.DisplayText.#ctor(Org.BouncyCastle.Asn1.IAsn1String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.DisplayText.GetString">
+             Returns the stored <code>string</code> object.
+            
+             @return the stored text as a <code>string</code>.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.DistributionPoint">
+            The DistributionPoint object.
+            <pre>
+            DistributionPoint ::= Sequence {
+                 distributionPoint [0] DistributionPointName OPTIONAL,
+                 reasons           [1] ReasonFlags OPTIONAL,
+                 cRLIssuer         [2] GeneralNames OPTIONAL
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.DistributionPointName">
+            The DistributionPointName object.
+            <pre>
+            DistributionPointName ::= CHOICE {
+                fullName                 [0] GeneralNames,
+                nameRelativeToCRLIssuer  [1] RDN
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.ExtendedKeyUsage">
+            The extendedKeyUsage object.
+            <pre>
+                 extendedKeyUsage ::= Sequence SIZE (1..MAX) OF KeyPurposeId
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.ExtendedKeyUsage.GetAllUsages">
+            Returns all extended key usages.
+            The returned ArrayList contains DerObjectIdentifier instances.
+            @return An ArrayList with all key purposes.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.GeneralName">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.GeneralName.#ctor(Org.BouncyCastle.Asn1.Asn1Object,System.Int32)">
+             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].
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.GeneralName.#ctor(System.Int32,System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.GeneralNames.#ctor(Org.BouncyCastle.Asn1.X509.GeneralName)">
+            <summary>Construct a GeneralNames object containing one GeneralName.</summary>
+            <param name="name">The name to be contained.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.GeneralNames.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            GeneralNames ::= Sequence SIZE {1..MAX} OF GeneralName
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.GeneralSubtree">
+             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
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.GeneralSubtree.#ctor(Org.BouncyCastle.Asn1.X509.GeneralName,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.GeneralSubtree.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Holder">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.#ctor(Org.BouncyCastle.Asn1.Asn1TaggedObject)">
+            Constructor for a holder for an v1 attribute certificate.
+            
+            @param tagObj The ASN.1 tagged holder object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            Constructor for a holder for an v2 attribute certificate. *
+            
+            @param seq The ASN.1 sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.#ctor(Org.BouncyCastle.Asn1.X509.IssuerSerial,System.Int32)">
+            Constructs a holder from a IssuerSerial.
+            @param baseCertificateID The IssuerSerial.
+            @param version The version of the attribute certificate. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.#ctor(Org.BouncyCastle.Asn1.X509.GeneralNames)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.#ctor(Org.BouncyCastle.Asn1.X509.GeneralNames,System.Int32)">
+            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. 
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.#ctor(Org.BouncyCastle.Asn1.X509.ObjectDigestInfo)">
+            Constructs a holder from an object digest info.
+            
+            @param objectDigestInfo The object digest info object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Holder.ToAsn1Object">
+            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>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.Holder.Version">
+            Returns 1 for v2 attribute certificates or 0 for v1 attribute
+            certificates. 
+            @return The version of the attribute certificate.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.Holder.EntityName">
+            Returns the entityName for an v2 attribute certificate or the subjectName
+            for an v1 attribute certificate.
+            
+            @return The entityname or subjectname.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.IetfAttrSyntax">
+            Implementation of <code>IetfAttrSyntax</code> as specified by RFC3281.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.IetfAttrSyntax.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.IetfAttrSyntax.ToAsn1Object">
+            
+             <pre>
+            
+              IetfAttrSyntax ::= Sequence {
+                policyAuthority [0] GeneralNames OPTIONAL,
+                values Sequence OF CHOICE {
+                  octets OCTET STRING,
+                  oid OBJECT IDENTIFIER,
+                  string UTF8String
+                }
+              }
+            
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.IssuerSerial.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             IssuerSerial  ::=  Sequence {
+                  issuer         GeneralNames,
+                  serial         CertificateSerialNumber,
+                  issuerUid      UniqueIdentifier OPTIONAL
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.IssuingDistributionPoint">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.IssuingDistributionPoint.#ctor(Org.BouncyCastle.Asn1.X509.DistributionPointName,System.Boolean,System.Boolean,Org.BouncyCastle.Asn1.X509.ReasonFlags,System.Boolean,System.Boolean)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.IssuingDistributionPoint.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            Constructor from Asn1Sequence
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.IssuingDistributionPoint.DistributionPoint">
+            @return Returns the distributionPoint.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.IssuingDistributionPoint.OnlySomeReasons">
+            @return Returns the onlySomeReasons.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.KeyPurposeID">
+            The KeyPurposeID object.
+            <pre>
+                KeyPurposeID ::= OBJECT IDENTIFIER
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.KeyUsage">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.KeyUsage.#ctor(System.Int32)">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.NameConstraints.#ctor(System.Collections.IList,System.Collections.IList)">
+             Constructor from a given details.
+            
+             <p>permitted and excluded are Vectors of GeneralSubtree objects.</p>
+            
+             @param permitted Permitted subtrees
+             @param excluded Excluded subtrees
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.NoticeReference">
+             <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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.NoticeReference.#ctor(System.String,System.Collections.IList)">
+             Creates a new <code>NoticeReference</code> instance.
+            
+             @param orgName a <code>string</code> value
+             @param numbers a <code>ArrayList</code> value
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.NoticeReference.#ctor(System.String,Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Creates a new <code>NoticeReference</code> instance.
+            
+             @param orgName a <code>string</code> value
+             @param numbers an <code>Asn1Sequence</code> value
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.NoticeReference.#ctor(System.Int32,System.String,Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.NoticeReference.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.NoticeReference.ToAsn1Object">
+             Describe <code>ToAsn1Object</code> method here.
+            
+             @return a <code>Asn1Object</code> value
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.ObjectDigestInfo">
+            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>
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.ObjectDigestInfo.PublicKey">
+            The public key is hashed.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.ObjectDigestInfo.PublicKeyCert">
+            The public key certificate is hashed.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.ObjectDigestInfo.OtherObjectDigest">
+            An other object is hashed.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.ObjectDigestInfo.#ctor(System.Int32,System.String,Org.BouncyCastle.Asn1.X509.AlgorithmIdentifier,System.Byte[])">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.ObjectDigestInfo.ToAsn1Object">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.PolicyMappings">
+             PolicyMappings V3 extension, described in RFC3280.
+             <pre>
+                PolicyMappings ::= Sequence SIZE (1..MAX) OF Sequence {
+                  issuerDomainPolicy      CertPolicyId,
+                  subjectDomainPolicy     CertPolicyId }
+             </pre>
+            
+             @see <a href="http://www.faqs.org/rfc/rfc3280.txt">RFC 3280, section 4.2.1.6</a>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.PolicyMappings.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Creates a new <code>PolicyMappings</code> instance.
+            
+             @param seq an <code>Asn1Sequence</code> constructed as specified
+             in RFC 3280
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.PolicyMappings.#ctor(System.Collections.IDictionary)">
+             Creates a new <code>PolicyMappings</code> instance.
+            
+             @param mappings a <code>HashMap</code> value that maps
+             <code>string</code> oids
+             to other <code>string</code> oids.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.PolicyQualifierID">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.PolicyQualifierInfo">
+             Policy qualifiers, used in the X509V3 CertificatePolicies
+             extension.
+            
+             <pre>
+               PolicyQualifierInfo ::= Sequence {
+                   policyQualifierId  PolicyQualifierId,
+                   qualifier          ANY DEFINED BY policyQualifierId }
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.PolicyQualifierInfo.#ctor(Org.BouncyCastle.Asn1.DerObjectIdentifier,Org.BouncyCastle.Asn1.Asn1Encodable)">
+             Creates a new <code>PolicyQualifierInfo</code> instance.
+            
+             @param policyQualifierId a <code>PolicyQualifierId</code> value
+             @param qualifier the qualifier, defined by the above field.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.PolicyQualifierInfo.#ctor(System.String)">
+             Creates a new <code>PolicyQualifierInfo</code> containing a
+             cPSuri qualifier.
+            
+             @param cps the CPS (certification practice statement) uri as a
+             <code>string</code>.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.PolicyQualifierInfo.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Creates a new <code>PolicyQualifierInfo</code> instance.
+            
+             @param as <code>PolicyQualifierInfo</code> X509 structure
+             encoded as an Asn1Sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.PolicyQualifierInfo.ToAsn1Object">
+             Returns a Der-encodable representation of this instance.
+            
+             @return a <code>Asn1Object</code> value
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.PrivateKeyUsagePeriod">
+            <remarks>
+            <pre>
+            PrivateKeyUsagePeriod ::= SEQUENCE
+            {
+            notBefore       [0]     GeneralizedTime OPTIONAL,
+            notAfter        [1]     GeneralizedTime OPTIONAL }
+            </pre>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Qualified.BiometricData">
+            The BiometricData object.
+            <pre>
+            BiometricData  ::=  SEQUENCE {
+                  typeOfBiometricData  TypeOfBiometricData,
+                  hashAlgorithm        AlgorithmIdentifier,
+                  biometricDataHash    OCTET STRING,
+                  sourceDataUri        IA5String OPTIONAL  }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Qualified.Iso4217CurrencyCode">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Qualified.MonetaryValue">
+            The MonetaryValue object.
+            <pre>
+            MonetaryValue  ::=  SEQUENCE {
+                  currency              Iso4217CurrencyCode,
+                  amount               INTEGER,
+                  exponent             INTEGER }
+            -- value = amount * 10^exponent
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Qualified.QCStatement">
+            The QCStatement object.
+            <pre>
+            QCStatement ::= SEQUENCE {
+              statementId        OBJECT IDENTIFIER,
+              statementInfo      ANY DEFINED BY statementId OPTIONAL}
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Qualified.SemanticsInformation">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Qualified.TypeOfBiometricData">
+             The TypeOfBiometricData object.
+             <pre>
+             TypeOfBiometricData ::= CHOICE {
+               predefinedBiometricType   PredefinedBiometricType,
+               biometricDataOid          OBJECT IDENTIFIER }
+            
+             PredefinedBiometricType ::= INTEGER {
+               picture(0),handwritten-signature(1)}
+               (picture|handwritten-signature)
+             </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.ReasonFlags">
+            The ReasonFlags object.
+            <pre>
+            ReasonFlags ::= BIT STRING {
+               unused(0),
+               keyCompromise(1),
+               cACompromise(2),
+               affiliationChanged(3),
+               superseded(4),
+               cessationOfOperation(5),
+               certficateHold(6)
+            }
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.ReasonFlags.#ctor(System.Int32)">
+            @param reasons - the bitwise OR of the Key Reason flags giving the
+            allowed uses for the key.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.RoleSyntax">
+             Implementation of the RoleSyntax object as specified by the RFC3281.
+            
+             <pre>
+             RoleSyntax ::= SEQUENCE {
+                             roleAuthority  [0] GeneralNames OPTIONAL,
+                             roleName       [1] GeneralName
+                       }
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.GetInstance(System.Object)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.#ctor(Org.BouncyCastle.Asn1.X509.GeneralNames,Org.BouncyCastle.Asn1.X509.GeneralName)">
+            Constructor.
+            @param roleAuthority the role authority of this RoleSyntax.
+            @param roleName    the role name of this RoleSyntax.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.#ctor(Org.BouncyCastle.Asn1.X509.GeneralName)">
+            Constructor. Invoking this constructor is the same as invoking
+            <code>new RoleSyntax(null, roleName)</code>.
+            @param roleName    the role name of this RoleSyntax.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.#ctor(System.String)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.GetRoleNameAsString">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.GetRoleAuthorityAsString">
+            Gets the role authority as a <code>string[]</code> object.
+            @return the role authority of this RoleSyntax represented as a
+            <code>string[]</code> array.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RoleSyntax.ToAsn1Object">
+             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>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.RoleSyntax.RoleAuthority">
+            Gets the role authority of this RoleSyntax.
+            @return    an instance of <code>GeneralNames</code> holding the
+            role authority of this RoleSyntax.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.RoleSyntax.RoleName">
+            Gets the role name of this RoleSyntax.
+            @return    an instance of <code>GeneralName</code> holding the
+            role name of this RoleSyntax.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.RsaPublicKeyStructure.ToAsn1Object">
+            This outputs the key in Pkcs1v2 format.
+            <pre>
+                 RSAPublicKey ::= Sequence {
+                                     modulus Integer, -- n
+                                     publicExponent Integer, -- e
+                                 }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym">
+            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
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym.#ctor(Org.BouncyCastle.Asn1.X500.DirectoryString)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym.#ctor(System.String)">
+             Constructor from a given details.
+            
+             @param pseudonym The pseudonym.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym.#ctor(Org.BouncyCastle.Asn1.X500.DirectoryString,Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Constructor from a given details.
+            
+             @param surname   The surname.
+             @param givenName A sequence of directory strings making up the givenName
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.SigI.PersonalData">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.PersonalData.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.PersonalData.#ctor(Org.BouncyCastle.Asn1.X509.SigI.NameOrPseudonym,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Asn1.DerGeneralizedTime,Org.BouncyCastle.Asn1.X500.DirectoryString,System.String,Org.BouncyCastle.Asn1.X500.DirectoryString)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SigI.PersonalData.ToAsn1Object">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers">
+            Object Identifiers of SigI specifciation (German Signature Law
+            Interoperability specification).
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers.IdSigIKP">
+            Key purpose IDs for German SigI (Signature Interoperability
+            Specification)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers.IdSigICP">
+            Certificate policy IDs for German SigI (Signature Interoperability
+            Specification)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers.IdSigION">
+            Other Name IDs for German SigI (Signature Interoperability Specification)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers.IdSigIKPDirectoryService">
+            To be used for for the generation of directory service certificates.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers.IdSigIONPersonalData">
+            ID for PersonalData
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.SigI.SigIObjectIdentifiers.IdSigICPSigConform">
+            Certificate is conform to german signature law.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes">
+             This extension may contain further X.500 attributes of the subject. See also
+             RFC 3039.
+            
+             <pre>
+                 SubjectDirectoryAttributes ::= Attributes
+                 Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+                 Attribute ::= SEQUENCE
+                 {
+                   type AttributeType
+                   values SET OF AttributeValue
+                 }
+            
+                 AttributeType ::= OBJECT IDENTIFIER
+                 AttributeValue ::= ANY DEFINED BY AttributeType
+             </pre>
+            
+             @see org.bouncycastle.asn1.x509.X509Name for AttributeType ObjectIdentifiers.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Constructor from Asn1Sequence.
+            
+             The sequence is of type SubjectDirectoryAttributes:
+            
+             <pre>
+                  SubjectDirectoryAttributes ::= Attributes
+                  Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+                  Attribute ::= SEQUENCE
+                  {
+                    type AttributeType
+                    values SET OF AttributeValue
+                  }
+            
+                  AttributeType ::= OBJECT IDENTIFIER
+                  AttributeValue ::= ANY DEFINED BY AttributeType
+             </pre>
+            
+             @param seq
+                        The ASN.1 sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes.#ctor(System.Collections.IList)">
+             Constructor from an ArrayList of attributes.
+            
+             The ArrayList consists of attributes of type {@link Attribute Attribute}
+            
+             @param attributes The attributes.
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes.ToAsn1Object">
+             Produce an object suitable for an Asn1OutputStream.
+            
+             Returns:
+            
+             <pre>
+                  SubjectDirectoryAttributes ::= Attributes
+                  Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+                  Attribute ::= SEQUENCE
+                  {
+                    type AttributeType
+                    values SET OF AttributeValue
+                  }
+            
+                  AttributeType ::= OBJECT IDENTIFIER
+                  AttributeValue ::= ANY DEFINED BY AttributeType
+             </pre>
+            
+             @return a DERObject
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.SubjectDirectoryAttributes.Attributes">
+            @return Returns the attributes.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.SubjectKeyIdentifier">
+            The SubjectKeyIdentifier object.
+            <pre>
+            SubjectKeyIdentifier::= OCTET STRING
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectKeyIdentifier.#ctor(Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo)">
+             Calculates the keyIdentifier using a SHA1 hash over the BIT STRING
+             from SubjectPublicKeyInfo as defined in RFC3280.
+            
+             @param spki the subject public key info.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectKeyIdentifier.CreateSha1KeyIdentifier(Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectKeyIdentifier.CreateTruncatedSha1KeyIdentifier(Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo.GetPublicKey">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            SubjectPublicKeyInfo ::= Sequence {
+                                     algorithm AlgorithmIdentifier,
+                                     publicKey BIT STRING }
+            </pre>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.SubjectPublicKeyInfo.PublicKeyData">
+            for when the public key is raw bits...
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Target">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Target.GetInstance(System.Object)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Target.#ctor(Org.BouncyCastle.Asn1.Asn1TaggedObject)">
+            Constructor from Asn1TaggedObject.
+            
+            @param tagObj The tagged object.
+            @throws ArgumentException if the encoding is wrong.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Target.#ctor(Org.BouncyCastle.Asn1.X509.Target.Choice,Org.BouncyCastle.Asn1.X509.GeneralName)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Target.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            
+            Returns:
+            
+            <pre>
+                Target  ::= CHOICE {
+                  targetName          [0] GeneralName,
+                  targetGroup         [1] GeneralName,
+                  targetCert          [2] TargetCert
+                }
+            </pre>
+            
+            @return an Asn1Object
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.Target.TargetGroup">
+            @return Returns the targetGroup.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.Target.TargetName">
+            @return Returns the targetName.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.TargetInformation">
+            Target information extension for attributes certificates according to RFC
+            3281.
+            
+            <pre>
+                      SEQUENCE OF Targets
+            </pre>
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.TargetInformation.GetInstance(System.Object)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.TargetInformation.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            Constructor from a Asn1Sequence.
+            
+            @param seq The Asn1Sequence.
+            @throws ArgumentException if the sequence does not contain
+                        correctly encoded Targets elements.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.TargetInformation.GetTargetsObjects">
+            Returns the targets in this target information extension.
+            <p>
+            The ArrayList is cloned before it is returned.</p>
+            
+            @return Returns the targets.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.TargetInformation.#ctor(Org.BouncyCastle.Asn1.X509.Targets)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.TargetInformation.#ctor(Org.BouncyCastle.Asn1.X509.Target[])">
+             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}.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.TargetInformation.ToAsn1Object">
+            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
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.Targets">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Targets.GetInstance(System.Object)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Targets.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+            Constructor from Asn1Sequence.
+            
+            @param targets The ASN.1 SEQUENCE.
+            @throws ArgumentException if the contents of the sequence are
+                        invalid.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Targets.#ctor(Org.BouncyCastle.Asn1.X509.Target[])">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Targets.GetTargets">
+            Returns the targets in an <code>ArrayList</code>.
+            <p>
+            The ArrayList is cloned before it is returned.</p>
+            
+            @return Returns the targets.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Targets.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            
+            Returns:
+            
+            <pre>
+                       Targets ::= SEQUENCE OF Target
+            </pre>
+            
+            @return an Asn1Object
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.TbsCertificateStructure">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.TbsCertificateList">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Time.#ctor(System.DateTime)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Time.ToDateTime">
+            <summary>
+            Return our time as DateTime.
+            </summary>
+            <returns>A date time.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.Time.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Time ::= CHOICE {
+                        utcTime        UTCTime,
+                        generalTime    GeneralizedTime }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.UserNotice">
+             <code>UserNotice</code> class, used in
+             <code>CertificatePolicies</code> X509 extensions (in policy
+             qualifiers).
+             <pre>
+             UserNotice ::= Sequence {
+                  noticeRef        NoticeReference OPTIONAL,
+                  explicitText     DisplayText OPTIONAL}
+            
+             </pre>
+            
+             @see PolicyQualifierId
+             @see PolicyInformation
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.UserNotice.#ctor(Org.BouncyCastle.Asn1.X509.NoticeReference,Org.BouncyCastle.Asn1.X509.DisplayText)">
+             Creates a new <code>UserNotice</code> instance.
+            
+             @param noticeRef a <code>NoticeReference</code> value
+             @param explicitText a <code>DisplayText</code> value
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.UserNotice.#ctor(Org.BouncyCastle.Asn1.X509.NoticeReference,System.String)">
+             Creates a new <code>UserNotice</code> instance.
+            
+             @param noticeRef a <code>NoticeReference</code> value
+             @param str the explicitText field as a string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.UserNotice.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.V1TbsCertificateGenerator">
+             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>
+            
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.V2AttributeCertificateInfoGenerator">
+             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>
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.V2AttributeCertificateInfoGenerator.AddAttribute(Org.BouncyCastle.Asn1.X509.AttributeX509)">
+            @param attribute
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.V2Form.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             V2Form ::= Sequence {
+                  issuerName            GeneralNames  OPTIONAL,
+                  baseCertificateID     [0] IssuerSerial  OPTIONAL,
+                  objectDigestInfo      [1] ObjectDigestInfo  OPTIONAL
+                    -- issuerName MUST be present in this profile
+                    -- baseCertificateID and objectDigestInfo MUST NOT
+                    -- be present in this profile
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.V2TbsCertListGenerator">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.V3TbsCertificateGenerator">
+             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>
+            
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509CertificateStructure">
+            an X509Certificate structure.
+            <pre>
+             Certificate ::= Sequence {
+                 tbsCertificate          TbsCertificate,
+                 signatureAlgorithm      AlgorithmIdentifier,
+                 signature               BIT STRING
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509DefaultEntryConverter">
+            The default converter for X509 DN entries when going from their
+            string value to ASN.1 strings.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509NameEntryConverter">
+                 * 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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509NameEntryConverter.ConvertHexEncoded(System.String,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509NameEntryConverter.CanBePrintable(System.String)">
+            return true if the passed in string can be represented without
+            loss as a PrintableString, false otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509NameEntryConverter.GetConvertedValue(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509DefaultEntryConverter.GetConvertedValue(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.String)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509Extension">
+            an object for the elements in the X.509 V3 extension block.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extension.ConvertValueToObject(Org.BouncyCastle.Asn1.X509.X509Extension)">
+            <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="T:System.ArgumentException">If conversion is not possible.</exception>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectDirectoryAttributes">
+            Subject Directory Attributes
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectKeyIdentifier">
+            Subject Key Identifier
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.KeyUsage">
+            Key Usage
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.PrivateKeyUsagePeriod">
+            Private Key Usage Period
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectAlternativeName">
+            Subject Alternative Name
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.IssuerAlternativeName">
+            Issuer Alternative Name
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.BasicConstraints">
+            Basic Constraints
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.CrlNumber">
+            CRL Number
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.ReasonCode">
+            Reason code
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.InstructionCode">
+            Hold Instruction Code
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.InvalidityDate">
+            Invalidity Date
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.DeltaCrlIndicator">
+            Delta CRL indicator
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.IssuingDistributionPoint">
+            Issuing Distribution Point
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.CertificateIssuer">
+            Certificate Issuer
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.NameConstraints">
+            Name Constraints
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.CrlDistributionPoints">
+            CRL Distribution Points
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.CertificatePolicies">
+            Certificate Policies
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.PolicyMappings">
+            Policy Mappings
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.AuthorityKeyIdentifier">
+            Authority Key Identifier
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.PolicyConstraints">
+            Policy Constraints
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.ExtendedKeyUsage">
+            Extended Key Usage
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.FreshestCrl">
+            Freshest CRL
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.InhibitAnyPolicy">
+            Inhibit Any Policy
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.AuthorityInfoAccess">
+            Authority Info Access
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.SubjectInfoAccess">
+            Subject Info Access
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.LogoType">
+            Logo Type
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.BiometricInfo">
+            BiometricInfo
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.QCStatements">
+            QCStatements
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.AuditIdentity">
+            Audit identity extension in attribute certificates.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.NoRevAvail">
+            NoRevAvail extension in attribute certificates.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Extensions.TargetInformation">
+            TargetInformation extension in attribute certificates.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extensions.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Constructor from Asn1Sequence.
+            
+             the extensions are a list of constructed sequences, either with (Oid, OctetString) or (Oid, Boolean, OctetString)
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extensions.#ctor(System.Collections.IDictionary)">
+            constructor from a table of extensions.
+            <p>
+            it's is assumed the table contains Oid/string pairs.</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extensions.#ctor(System.Collections.IList,System.Collections.IDictionary)">
+            Constructor from a table of extensions with ordering.
+            <p>
+            It's is assumed the table contains Oid/string pairs.</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extensions.#ctor(System.Collections.IList,System.Collections.IList)">
+             Constructor from two vectors
+            
+             @param objectIDs an ArrayList of the object identifiers.
+             @param values an ArrayList of the extension values.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extensions.GetExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             return the extension represented by the object identifier
+             passed in.
+            
+             @return the extension if it's present, null otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Extensions.ToAsn1Object">
+             <pre>
+                 Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
+            
+                 Extension         ::=   SEQUENCE {
+                    extnId            EXTENSION.&amp;id ({ExtensionSet}),
+                    critical          BOOLEAN DEFAULT FALSE,
+                    extnValue         OCTET STRING }
+             </pre>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.X509Extensions.ExtensionOids">
+            return an Enumeration of the extension field's object ids.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509ExtensionsGenerator">
+            <remarks>Generator for X.509 extensions</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509ExtensionsGenerator.Reset">
+            <summary>Reset the generator</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509ExtensionsGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509ExtensionsGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,System.Byte[])">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509ExtensionsGenerator.Generate">
+            <summary>Generate an X509Extensions object based on the current state of the generator.</summary>
+            <returns>An <c>X509Extensions</c> object</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.X509ExtensionsGenerator.IsEmpty">
+            <summary>Return true if there are no extension present in this generator.</summary>
+            <returns>True if empty, false otherwise</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509Name">
+             <pre>
+                 RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+            
+                 RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+            
+                 AttributeTypeAndValue ::= SEQUENCE {
+                                               type  OBJECT IDENTIFIER,
+                                               value ANY }
+             </pre>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.C">
+            country code - StringType(SIZE(2))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.O">
+            organization - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.OU">
+            organizational unit name - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.T">
+            Title
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.CN">
+            common name - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.Street">
+            street - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.SerialNumber">
+            device serial number name - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.L">
+            locality name - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.ST">
+            state, or province name - StringType(SIZE(1..64))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.Surname">
+            Naming attributes of type X520name
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.BusinessCategory">
+            businessCategory - DirectoryString(SIZE(1..128)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.PostalCode">
+            postalCode - DirectoryString(SIZE(1..40)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.DnQualifier">
+            dnQualifier - DirectoryString(SIZE(1..64)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.Pseudonym">
+            RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.DateOfBirth">
+            RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.PlaceOfBirth">
+            RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.Gender">
+            RFC 3039 DateOfBirth - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.CountryOfCitizenship">
+            RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+            codes only
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.CountryOfResidence">
+            RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
+            codes only
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.NameAtBirth">
+            ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.PostalAddress">
+            RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
+            DirectoryString(SIZE(1..30))
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.DmdName">
+            RFC 2256 dmdName
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.TelephoneNumber">
+            id-at-telephoneNumber
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.Name">
+            id-at-name
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.EmailAddress">
+            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>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.UnstructuredName">
+            more from PKCS#9
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.E">
+            email address in Verisign certificates
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.UID">
+            LDAP User id.
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.DefaultSymbols">
+            default look up table translating OID values into their common symbols following
+            the convention in RFC 2253 with a few extras
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.RFC2253Symbols">
+            look up table translating OID values into their common symbols following the convention in RFC 2253
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.RFC1779Symbols">
+             look up table translating OID values into their common symbols following the convention in RFC 1779
+            
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X509.X509Name.DefaultLookup">
+            look up table translating common symbols into their OIDS.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.GetInstance(Org.BouncyCastle.Asn1.Asn1TaggedObject,System.Boolean)">
+             Return a X509Name based on the passed in tagged object.
+            
+             @param obj tag object holding name.
+             @param explicitly true if explicitly tagged false otherwise.
+             @return the X509Name
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Constructor from Asn1Sequence
+            
+             the principal will be a list of constructed sets, each containing an (OID, string) pair.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Collections.IList,System.Collections.IDictionary)">
+            Constructor from a table of attributes with ordering.
+            <p>
+            it's is assumed the table contains OID/string pairs, and the contents
+            of the table are copied into an internal table as part of the
+            construction process. The ordering ArrayList should contain the OIDs
+            in the order they are meant to be encoded or printed in ToString.</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Collections.IList,System.Collections.IDictionary,Org.BouncyCastle.Asn1.X509.X509NameEntryConverter)">
+            Constructor from a table of attributes with ordering.
+            <p>
+            it's is assumed the table contains OID/string pairs, and the contents
+            of the table are copied into an internal table as part of the
+            construction process. The ordering ArrayList should contain the OIDs
+            in the order they are meant to be encoded or printed in ToString.</p>
+            <p>
+            The passed in converter will be used to convert the strings into their
+            ASN.1 counterparts.</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Collections.IList,System.Collections.IList)">
+            Takes two vectors one of the oids and the other of the values.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Collections.IList,System.Collections.IList,Org.BouncyCastle.Asn1.X509.X509NameEntryConverter)">
+            Takes two vectors one of the oids and the other of the values.
+            <p>
+            The passed in converter will be used to convert the strings into their
+            ASN.1 counterparts.</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.String)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.String,Org.BouncyCastle.Asn1.X509.X509NameEntryConverter)">
+            Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+            some such, converting it into an ordered set of name attributes with each
+            string value being converted to its associated ASN.1 type using the passed
+            in converter.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Boolean,System.String)">
+            Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+            some such, converting it into an ordered set of name attributes. If reverse
+            is true, create the encoded version of the sequence starting from the
+            last element in the string.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Boolean,System.String,Org.BouncyCastle.Asn1.X509.X509NameEntryConverter)">
+            Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+            some such, converting it into an ordered set of name attributes with each
+            string value being converted to its associated ASN.1 type using the passed
+            in converter. If reverse is true the ASN.1 sequence representing the DN will
+            be built by starting at the end of the string, rather than the start.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Boolean,System.Collections.IDictionary,System.String)">
+            Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+            some such, converting it into an ordered set of name attributes. lookUp
+            should provide a table of lookups, indexed by lowercase only strings and
+            yielding a DerObjectIdentifier, other than that OID. and numeric oids
+            will be processed automatically.
+            <br/>
+            If reverse is true, create the encoded version of the sequence
+            starting from the last element in the string.
+            @param reverse true if we should start scanning from the end (RFC 2553).
+            @param lookUp table of names and their oids.
+            @param dirName the X.500 string to be parsed.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.#ctor(System.Boolean,System.Collections.IDictionary,System.String,Org.BouncyCastle.Asn1.X509.X509NameEntryConverter)">
+            Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+            some such, converting it into an ordered set of name attributes. lookUp
+            should provide a table of lookups, indexed by lowercase only strings and
+            yielding a DerObjectIdentifier, other than that OID. and numeric oids
+            will be processed automatically. The passed in converter is used to convert the
+            string values to the right of each equals sign to their ASN.1 counterparts.
+            <br/>
+            @param reverse true if we should start scanning from the end, false otherwise.
+            @param lookUp table of names and oids.
+            @param dirName the string dirName
+            @param converter the converter to convert string values into their ASN.1 equivalents
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.GetOidList">
+            return an IList of the oids in the name, in the order they were found.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.GetValueList">
+            return an IList of the values found in the name, in the order they
+            were found.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.GetValueList(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.Equivalent(Org.BouncyCastle.Asn1.X509.X509Name,System.Boolean)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.Equivalent(Org.BouncyCastle.Asn1.X509.X509Name)">
+            test for equivalence - note: case is ignored.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X509.X509Name.ToString(System.Boolean,System.Collections.IDictionary)">
+             convert the structure to a string - if reverse is true the
+             oids and values are listed out starting with the last element
+             in the sequence (ala RFC 2253), otherwise the string will begin
+             with the first element of the structure. If no string definition
+             for the oid is found in oidSymbols the string value of the oid is
+             added. Two standard symbol tables are provided DefaultSymbols, and
+             RFC2253Symbols as part of this class.
+            
+             @param reverse if true start at the end of the sequence and work back.
+             @param oidSymbols look up table strings for oids.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X509.X509Name.DefaultReverse">
+            determines whether or not strings should be processed and printed
+            from back to front.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X509.X509NameTokenizer">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.KeySpecificInfo">
+            ASN.1 def for Diffie-Hellman key exchange KeySpecificInfo structure. See
+            RFC 2631, or X9.42, for further details.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.KeySpecificInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             KeySpecificInfo ::= Sequence {
+                 algorithm OBJECT IDENTIFIER,
+                 counter OCTET STRING SIZE (4..4)
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.OtherInfo">
+            ANS.1 def for Diffie-Hellman key exchange OtherInfo structure. See
+            RFC 2631, or X9.42, for further details.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.OtherInfo.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             OtherInfo ::= Sequence {
+                 keyInfo KeySpecificInfo,
+                 partyAInfo [0] OCTET STRING OPTIONAL,
+                 suppPubInfo [2] OCTET STRING
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.X962NamedCurves">
+            table of the current named curves defined in X.962 EC-DSA.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X962NamedCurves.GetByOid(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X962NamedCurves.GetOid(System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X962NamedCurves.GetName(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            return the named curve name represented by the given object identifier.
+        </member>
+        <member name="P:Org.BouncyCastle.Asn1.X9.X962NamedCurves.Names">
+            returns an enumeration containing the name strings for curves
+            contained in this structure.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X962Parameters.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+            Parameters ::= CHOICE {
+               ecParameters ECParameters,
+               namedCurve   CURVES.&amp;id({CurveNames}),
+               implicitlyCA Null
+            }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.X9Curve">
+            ASN.1 def for Elliptic-Curve Curve structure. See
+            X9.62, for further details.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9Curve.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             Curve ::= Sequence {
+                 a               FieldElement,
+                 b               FieldElement,
+                 seed            BIT STRING      OPTIONAL
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.X9ECParameters">
+            ASN.1 def for Elliptic-Curve ECParameters structure. See
+            X9.62, for further details.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9ECParameters.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             ECParameters ::= Sequence {
+                 version         Integer { ecpVer1(1) } (ecpVer1),
+                 fieldID         FieldID {{FieldTypes}},
+                 curve           X9Curve,
+                 base            X9ECPoint,
+                 order           Integer,
+                 cofactor        Integer OPTIONAL
+             }
+            </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.X9ECPoint">
+            class for describing an ECPoint as a Der object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9ECPoint.ToAsn1Object">
+            Produce an object suitable for an Asn1OutputStream.
+            <pre>
+             ECPoint ::= OCTET STRING
+            </pre>
+            <p>
+            Octet string produced using ECPoint.GetEncoded().</p>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.X9FieldElement">
+            Class for processing an ECFieldElement as a DER object.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9FieldElement.ToAsn1Object">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Asn1.X9.X9FieldID">
+            ASN.1 def for Elliptic-Curve Field ID structure. See
+            X9.62, for further details.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9FieldID.#ctor(Org.BouncyCastle.Math.BigInteger)">
+            Constructor for elliptic curves over prime fields
+            <code>F<sub>2</sub></code>.
+            @param primeP The prime <code>p</code> defining the prime field.
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9FieldID.#ctor(System.Int32,System.Int32,System.Int32,System.Int32)">
+            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>..
+        </member>
+        <member name="M:Org.BouncyCastle.Asn1.X9.X9FieldID.ToAsn1Object">
+            Produce a Der encoding of the following structure.
+            <pre>
+             FieldID ::= Sequence {
+                 fieldType       FIELD-ID.&amp;id({IOSet}),
+                 parameters      FIELD-ID.&amp;Type({IOSet}{&#64;fieldType})
+             }
+            </pre>
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X9.X9ObjectIdentifiers.AnsiX942">
+            X9.42
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X9.X9ObjectIdentifiers.IdDsaWithSha1">
+            id-dsa-with-sha1 OBJECT IDENTIFIER ::=  { iso(1) member-body(2)
+                  us(840) x9-57 (10040) x9cm(4) 3 }
+        </member>
+        <member name="F:Org.BouncyCastle.Asn1.X9.X9ObjectIdentifiers.X9x63Scheme">
+            X9.63
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ArmoredInputStream">
+            reader for Base64 armored objects - read the headers and then start returning
+            bytes when the data is reached. An IOException is thrown if the CRC check
+            fails.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.Decode(System.Int32,System.Int32,System.Int32,System.Int32,System.Int32[])">
+             decode the base 64 encoded input data.
+            
+             @return the offset the data starts in out.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.#ctor(System.IO.Stream)">
+             Create a stream for reading a PGP armoured message, parsing up to a header
+             and then reading the data that follows.
+            
+             @param input
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.#ctor(System.IO.Stream,System.Boolean)">
+             Create an armoured input stream which will assume the data starts
+             straight away, or parse for headers first depending on the value of
+             hasHeaders.
+            
+             @param input
+             @param hasHeaders true if headers are to be looked for, false otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.IsClearText">
+            @return true if we are inside the clear text section of a PGP
+            signed message.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.IsEndOfStream">
+            @return true if the stream is actually at end of file.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.GetArmorHeaderLine">
+            Return the armor header line (if there is one)
+            @return the armor header line, null if none present.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredInputStream.GetArmorHeaders">
+            Return the armor headers (the lines after the armor header line),
+            @return an array of armor headers, null if there aren't any.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ArmoredOutputStream">
+            Basic output stream.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredOutputStream.Encode(System.IO.Stream,System.Int32[],System.Int32)">
+            encode the input data producing a base 64 encoded byte array.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredOutputStream.SetHeader(System.String,System.String)">
+             Set an additional header entry.
+            
+             @param name the name of the header entry.
+             @param v the value of the header entry.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredOutputStream.ResetHeaders">
+            Reset the headers to only contain a Version string.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredOutputStream.BeginClearText(Org.BouncyCastle.Bcpg.HashAlgorithmTag)">
+            Start a clear text signed message.
+            @param hashAlgorithm
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ArmoredOutputStream.Dispose(System.Boolean)">
+            <b>Note</b>: Dispose does nor Dispose the underlying stream. So it is possible to write
+            multiple objects using armoring to a single stream.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Attr.ImageAttrib">
+            <remarks>Basic type for a image attribute packet.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.UserAttributeSubpacket">
+            Basic type for a user attribute sub-packet.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.UserAttributeSubpacket.GetData">
+            return the generic data making up the packet.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.BcpgInputStream">
+            <remarks>Reader for PGP objects.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgInputStream.NextPacketTag">
+            <summary>Returns the next packet tag in the stream.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.BcpgInputStream.PartialInputStream">
+            <summary>
+            A stream that overlays our input stream, allowing the user to only read a segment of it.
+            NB: dataLength will be negative if the segment length is in the upper range above 2**31.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.BcpgObject">
+            <remarks>Base class for a PGP object.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.BcpgOutputStream">
+            <remarks>Basic output stream.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.#ctor(System.IO.Stream)">
+            <summary>Create a stream representing a general packet.</summary>
+            <param name="outStr">Output stream to write to.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.#ctor(System.IO.Stream,Org.BouncyCastle.Bcpg.PacketTag)">
+            <summary>Create a stream representing an old style partial object.</summary>
+            <param name="outStr">Output stream to write to.</param>
+            <param name="tag">The packet tag for the object.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.#ctor(System.IO.Stream,Org.BouncyCastle.Bcpg.PacketTag,System.Int64,System.Boolean)">
+            <summary>Create a stream representing a general packet.</summary>
+            <param name="outStr">Output stream to write to.</param>
+            <param name="tag">Packet tag.</param>
+            <param name="length">Size of chunks making up the packet.</param>
+            <param name="oldFormat">If true, the header is written out in old format.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.#ctor(System.IO.Stream,Org.BouncyCastle.Bcpg.PacketTag,System.Int64)">
+            <summary>Create a new style partial input stream buffered into chunks.</summary>
+            <param name="outStr">Output stream to write to.</param>
+            <param name="tag">Packet tag.</param>
+            <param name="length">Size of chunks making up the packet.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.#ctor(System.IO.Stream,Org.BouncyCastle.Bcpg.PacketTag,System.Byte[])">
+            <summary>Create a new style partial input stream buffered into chunks.</summary>
+            <param name="outStr">Output stream to write to.</param>
+            <param name="tag">Packet tag.</param>
+            <param name="buffer">Buffer to use for collecting chunks.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.Flush">
+            <summary>Flush the underlying stream.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.BcpgOutputStream.Finish">
+            <summary>Finish writing out the current packet without closing the underlying stream.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.CompressedDataPacket">
+            <remarks>Generic compressed data object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.InputStreamPacket.GetInputStream">
+            <summary>Note: you can only read from this once...</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.CompressedDataPacket.Algorithm">
+            <summary>The algorithm tag value.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.CompressionAlgorithmTag">
+            <remarks>Basic tags for compression algorithms.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ContainedPacket">
+            <remarks>Basic type for a PGP packet.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.DsaPublicBcpgKey">
+            <remarks>Base class for a DSA public key.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.IBcpgKey">
+            <remarks>Base interface for a PGP key.</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.IBcpgKey.Format">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.DsaPublicBcpgKey.#ctor(Org.BouncyCastle.Bcpg.BcpgInputStream)">
+            <param name="bcpgIn">The stream to read the packet from.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.DsaPublicBcpgKey.GetEncoded">
+            <summary>Return the standard PGP encoding of the key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.DsaPublicBcpgKey.Format">
+            <summary>The format, as a string, always "PGP".</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.DsaSecretBcpgKey">
+            <remarks>Base class for a DSA secret key.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.DsaSecretBcpgKey.#ctor(Org.BouncyCastle.Bcpg.BcpgInputStream)">
+            @param in
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.DsaSecretBcpgKey.GetEncoded">
+            <summary>Return the standard PGP encoding of the key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.DsaSecretBcpgKey.Format">
+            <summary>The format, as a string, always "PGP".</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.DsaSecretBcpgKey.X">
+            @return x
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ElGamalPublicBcpgKey">
+            <remarks>Base class for an ElGamal public key.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ElGamalPublicBcpgKey.GetEncoded">
+            <summary>Return the standard PGP encoding of the key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.ElGamalPublicBcpgKey.Format">
+            <summary>The format, as a string, always "PGP".</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ElGamalSecretBcpgKey">
+            <remarks>Base class for an ElGamal secret key.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ElGamalSecretBcpgKey.#ctor(Org.BouncyCastle.Bcpg.BcpgInputStream)">
+            @param in
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ElGamalSecretBcpgKey.#ctor(Org.BouncyCastle.Math.BigInteger)">
+            @param x
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.ElGamalSecretBcpgKey.GetEncoded">
+            <summary>Return the standard PGP encoding of the key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.ElGamalSecretBcpgKey.Format">
+            <summary>The format, as a string, always "PGP".</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ExperimentalPacket">
+            <remarks>Basic packet for an experimental packet.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.HashAlgorithmTag">
+            <remarks>Basic tags for hash algorithms.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.LiteralDataPacket">
+            <remarks>Generic literal data packet.</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.LiteralDataPacket.Format">
+            <summary>The format tag value.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.LiteralDataPacket.ModificationTime">
+            <summary>The modification time of the file in milli-seconds (since Jan 1, 1970 UTC)</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.MarkerPacket">
+            <remarks>Basic type for a marker packet.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.ModDetectionCodePacket">
+            <remarks>Basic packet for a modification detection code packet.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.MPInteger">
+            <remarks>A multiple precision integer</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OnePassSignaturePacket">
+            <remarks>Generic signature object</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OnePassSignaturePacket.KeyAlgorithm">
+            <summary>The encryption algorithm tag.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OnePassSignaturePacket.HashAlgorithm">
+            <summary>The hash algorithm tag.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.PacketTag">
+            <remarks>Basic PGP packet tag types.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag">
+            <remarks>Public Key Algorithm tag numbers.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.PublicKeyEncSessionPacket">
+            <remarks>Basic packet for a PGP public key.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.PublicKeyPacket">
+            <remarks>Basic packet for a PGP public key.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.PublicKeyPacket.#ctor(Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,System.DateTime,Org.BouncyCastle.Bcpg.IBcpgKey)">
+            <summary>Construct a version 4 public key packet.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.PublicSubkeyPacket">
+            <remarks>Basic packet for a PGP public subkey</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.PublicSubkeyPacket.#ctor(Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,System.DateTime,Org.BouncyCastle.Bcpg.IBcpgKey)">
+            <summary>Construct a version 4 public subkey packet.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.RsaPublicBcpgKey">
+            <remarks>Base class for an RSA public key.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.RsaPublicBcpgKey.#ctor(Org.BouncyCastle.Bcpg.BcpgInputStream)">
+            <summary>Construct an RSA public key from the passed in stream.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.RsaPublicBcpgKey.#ctor(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            <param name="n">The modulus.</param>
+            <param name="e">The public exponent.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.RsaPublicBcpgKey.GetEncoded">
+            <summary>Return the standard PGP encoding of the key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.RsaPublicBcpgKey.Format">
+            <summary>The format, as a string, always "PGP".</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.RsaSecretBcpgKey">
+            <remarks>Base class for an RSA secret (or priate) key.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.RsaSecretBcpgKey.GetEncoded">
+            <summary>Return the standard PGP encoding of the key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.RsaSecretBcpgKey.Format">
+            <summary>The format, as a string, always "PGP".</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.S2k">
+            <remarks>The string to key specifier class.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.S2k.GetIV">
+            <summary>The IV for the key generation algorithm.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.S2k.HashAlgorithm">
+            <summary>The hash algorithm.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.S2k.IterationCount">
+            <summary>The iteration count</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.S2k.ProtectionMode">
+            <summary>The protection mode - only if GnuDummyS2K</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SecretKeyPacket">
+            <remarks>Basic packet for a PGP secret key.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SecretSubkeyPacket">
+            <remarks>Basic packet for a PGP secret key.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SignaturePacket">
+            <remarks>Generic signature packet.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SignaturePacket.#ctor(System.Int32,System.Int64,Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,Org.BouncyCastle.Bcpg.HashAlgorithmTag,Org.BouncyCastle.Bcpg.SignatureSubpacket[],Org.BouncyCastle.Bcpg.SignatureSubpacket[],System.Byte[],Org.BouncyCastle.Bcpg.MPInteger[])">
+             Generate a version 4 signature packet.
+            
+             @param signatureType
+             @param keyAlgorithm
+             @param hashAlgorithm
+             @param hashedData
+             @param unhashedData
+             @param fingerprint
+             @param signature
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SignaturePacket.#ctor(System.Int32,System.Int32,System.Int64,Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,Org.BouncyCastle.Bcpg.HashAlgorithmTag,System.Int64,System.Byte[],Org.BouncyCastle.Bcpg.MPInteger[])">
+             Generate a version 2/3 signature packet.
+            
+             @param signatureType
+             @param keyAlgorithm
+             @param hashAlgorithm
+             @param fingerprint
+             @param signature
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SignaturePacket.GetSignatureTrailer">
+             return the signature trailer that must be included with the data
+             to reconstruct the signature
+            
+             @return byte[]
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SignaturePacket.GetSignature">
+            		* 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SignaturePacket.GetSignatureBytes">
+            Return the byte encoding of the signature section.
+            @return uninterpreted signature bytes.
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.SignaturePacket.KeyId">
+            return the keyId
+            @return the keyId that created the signature.
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.SignaturePacket.CreationTime">
+            <summary>Return the creation time in milliseconds since 1 Jan., 1970 UTC.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SignatureSubpacket">
+            <remarks>Basic type for a PGP Signature sub-packet.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SignatureSubpacket.GetData">
+            <summary>Return the generic data making up the packet.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SignatureSubpacketsParser">
+            reader for signature sub-packets
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SignatureSubpacketTag">
+            Basic PGP signature sub-packet tag types.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.EmbeddedSignature">
+            Packet embedded signature
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.Exportable">
+            packet giving signature creation time.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.IssuerKeyId">
+            packet giving signature creation time.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.KeyExpirationTime">
+            packet giving time after creation at which the key expires.
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.Sig.KeyExpirationTime.Time">
+             Return the number of seconds after creation time a key is valid for.
+            
+             @return second count for key validity.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.KeyFlags">
+            Packet holding the key flag values.
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.Sig.KeyFlags.Flags">
+            <summary>
+            Return the flag values contained in the first 4 octets (note: at the moment
+            the standard only uses the first one).
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.NotationData">
+            Class provided a NotationData object according to
+            RFC2440, Chapter 5.2.3.15. Notation Data
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.PreferredAlgorithms">
+            packet giving signature creation time.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.PrimaryUserId">
+            packet giving whether or not the signature is signed using the primary user ID for the key.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.Revocable">
+            packet giving whether or not is revocable.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.RevocationKey">
+            <summary>
+            Represents revocation key OpenPGP signature sub packet.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.RevocationReason">
+            <summary>
+            Represents revocation reason OpenPGP signature sub packet.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.SignatureCreationTime">
+            packet giving signature creation time.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.SignatureExpirationTime">
+            packet giving signature expiration time.
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.Sig.SignatureExpirationTime.Time">
+            return time in seconds before signature expires after creation time.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.SignerUserId">
+            packet giving the User ID of the signer.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.Sig.TrustSignature">
+            packet giving trust.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SymmetricEncDataPacket">
+            <remarks>Basic type for a symmetric key encrypted packet.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag">
+            Basic tags for symmetric key algorithms
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.SymmetricKeyEncSessionPacket">
+            Basic type for a symmetric encrypted session key packet
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.SymmetricKeyEncSessionPacket.GetSecKeyData">
+            @return byte[]
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.SymmetricKeyEncSessionPacket.EncAlgorithm">
+            @return int
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.SymmetricKeyEncSessionPacket.S2k">
+            @return S2k
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.SymmetricKeyEncSessionPacket.Version">
+            @return int
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.TrustPacket">
+            <summary>Basic type for a trust packet.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.UserAttributePacket">
+            Basic type for a user attribute packet.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.UserAttributeSubpacketsParser">
+            reader for user attribute sub-packets
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.UserAttributeSubpacketTag">
+            Basic PGP user attribute sub-packet tag types.
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.UserIdPacket">
+            Basic type for a user ID packet.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsAttributeTableParameter">
+            <remarks>
+            The 'Signature' parameter is only available when generating unsigned attributes.
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsAuthenticatedData">
+            containing class for an CMS Authenticated Data object
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedData.GetRecipientInfos">
+            return a store of the intended recipients for this message
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedData.GetAuthAttrs">
+            return a table of the digested attributes indexed by
+            the OID of the attribute.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedData.GetUnauthAttrs">
+            return a table of the undigested attributes indexed by
+            the OID of the attribute.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedData.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsAuthenticatedData.MacAlgOid">
+            return the object identifier for the content MAC algorithm.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsAuthenticatedData.ContentInfo">
+            return the ContentInfo 
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsAuthenticatedDataGenerator">
+             General class for generating a CMS authenticated-data message.
+            
+             A simple example of usage.
+            
+             <pre>
+                  CMSAuthenticatedDataGenerator  fact = new CMSAuthenticatedDataGenerator();
+            
+                  fact.addKeyTransRecipient(cert);
+            
+                  CMSAuthenticatedData         data = fact.generate(content, algorithm, "BC");
+             </pre>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsEnvelopedGenerator">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Constructor allowing specific source of randomness</summary>
+            <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.AddKeyTransRecipient(Org.BouncyCastle.X509.X509Certificate)">
+             add a recipient.
+            
+             @param cert recipient's public key certificate
+             @exception ArgumentException if there is a problem with the certificate
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.AddKeyTransRecipient(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[])">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.AddKekRecipient(System.String,Org.BouncyCastle.Crypto.Parameters.KeyParameter,System.Byte[])">
+            add a KEK recipient.
+            @param key the secret key to use for wrapping
+            @param keyIdentifier the byte string that identifies the key
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.AddKekRecipient(System.String,Org.BouncyCastle.Crypto.Parameters.KeyParameter,Org.BouncyCastle.Asn1.Cms.KekIdentifier)">
+            add a KEK recipient.
+            @param key the secret key to use for wrapping
+            @param keyIdentifier the byte string that identifies the key
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.AddKeyAgreementRecipient(System.String,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedGenerator.AddKeyAgreementRecipients(System.String,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Collections.ICollection,System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedGenerator.#ctor">
+            base constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+             constructor allowing specific source of randomness
+            
+             @param rand instance of SecureRandom to use
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataGenerator.#ctor">
+            base constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            constructor allowing specific source of randomness
+            @param rand instance of SecureRandom to use
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.String,Org.BouncyCastle.Crypto.CipherKeyGenerator)">
+            generate an enveloped object that contains an CMS Enveloped Data
+            object using the given provider and the passed in key generator.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.String)">
+            generate an authenticated object that contains an CMS Authenticated Data object
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsAuthenticatedDataParser">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsContentInfoParser.Close">
+            Close the underlying data stream.
+            @throws IOException if the close fails.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataParser.GetRecipientInfos">
+            return a store of the intended recipients for this message
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataParser.GetAuthAttrs">
+            return a table of the unauthenticated attributes indexed by
+            the OID of the attribute.
+            @exception java.io.IOException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataParser.GetUnauthAttrs">
+            return a table of the unauthenticated attributes indexed by
+            the OID of the attribute.
+            @exception java.io.IOException
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsAuthenticatedDataParser.MacAlgOid">
+            return the object identifier for the mac algorithm.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsAuthenticatedDataParser.MacAlgParams">
+            return the ASN.1 encoded encryption algorithm parameters, or null if
+            there aren't any.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator">
+             General class for generating a CMS authenticated-data message stream.
+             <p>
+             A simple example of usage.
+             <pre>
+                  CMSAuthenticatedDataStreamGenerator edGen = new CMSAuthenticatedDataStreamGenerator();
+            
+                  edGen.addKeyTransRecipient(cert);
+            
+                  ByteArrayOutputStream  bOut = new ByteArrayOutputStream();
+            
+                  OutputStream out = edGen.open(
+                                          bOut, CMSAuthenticatedDataGenerator.AES128_CBC, "BC");*
+                  out.write(data);
+            
+                  out.close();
+             </pre>
+             </p>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.#ctor">
+            base constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            constructor allowing specific source of randomness
+            @param rand instance of SecureRandom to use
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.SetBufferSize(System.Int32)">
+             Set the underlying string size for encapsulated data
+            
+             @param bufferSize length of octet strings to buffer the data.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.SetBerEncodeRecipients(System.Boolean)">
+            Use a BER Set to store the recipient information
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.Open(System.IO.Stream,System.String,Org.BouncyCastle.Crypto.CipherKeyGenerator)">
+            generate an enveloped object that contains an CMS Enveloped Data
+            object using the given provider and the passed in key generator.
+            @throws java.io.IOException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.Open(System.IO.Stream,System.String)">
+            generate an enveloped object that contains an CMS Enveloped Data object
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsAuthenticatedDataStreamGenerator.Open(System.IO.Stream,System.String,System.Int32)">
+            generate an enveloped object that contains an CMS Enveloped Data object
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsAuthEnvelopedData">
+            containing class for an CMS AuthEnveloped Data object
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsCompressedData">
+            containing class for an CMS Compressed Data object
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsCompressedData.GetContent">
+             Return the uncompressed content.
+            
+             @return the uncompressed content
+             @throws CmsException if there is an exception uncompressing the data.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsCompressedData.GetContent(System.Int32)">
+             Return the uncompressed content, throwing an exception if the data size
+             is greater than the passed in limit. If the content is exceeded getCause()
+             on the CMSException will contain a StreamOverflowException
+            
+             @param limit maximum number of bytes to read
+             @return the content read
+             @throws CMSException if there is an exception uncompressing the data.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsCompressedData.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsCompressedData.ContentInfo">
+            return the ContentInfo 
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsCompressedDataGenerator">
+                * General class for generating a compressed CMS message.
+                * <p>
+                * A simple example of usage.</p>
+                * <p>
+                * <pre>
+                *      CMSCompressedDataGenerator fact = new CMSCompressedDataGenerator();
+                *      CMSCompressedData data = fact.Generate(content, algorithm);
+                * </pre>
+            	* </p>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsCompressedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.String)">
+            Generate an object that contains an CMS Compressed Data
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsCompressedDataParser">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsCompressedDataStreamGenerator">
+             General class for generating a compressed CMS message stream.
+             <p>
+             A simple example of usage.
+             </p>
+             <pre>
+                  CMSCompressedDataStreamGenerator gen = new CMSCompressedDataStreamGenerator();
+            
+                  Stream cOut = gen.Open(outputStream, CMSCompressedDataStreamGenerator.ZLIB);
+            
+                  cOut.Write(data);
+            
+                  cOut.Close();
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsCompressedDataStreamGenerator.#ctor">
+            base constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsCompressedDataStreamGenerator.SetBufferSize(System.Int32)">
+             Set the underlying string size for encapsulated data
+            
+             @param bufferSize length of octet strings to buffer the data.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsEnvelopedData">
+            containing class for an CMS Enveloped Data object
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedData.GetRecipientInfos">
+            return a store of the intended recipients for this message
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedData.GetUnprotectedAttributes">
+            return a table of the unprotected attributes indexed by
+            the OID of the attribute.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedData.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsEnvelopedData.EncryptionAlgOid">
+            return the object identifier for the content encryption algorithm.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsEnvelopedData.ContentInfo">
+            return the ContentInfo 
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsEnvelopedDataGenerator">
+             <remarks>
+             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);
+             </pre>
+             </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Constructor allowing specific source of randomness</summary>
+            <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.String,Org.BouncyCastle.Crypto.CipherKeyGenerator)">
+            <summary>
+            Generate an enveloped object that contains a CMS Enveloped Data
+            object using the passed in key generator.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.String)">
+            <summary>Generate an enveloped object that contains an CMS Enveloped Data object.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.String,System.Int32)">
+            <summary>Generate an enveloped object that contains an CMS Enveloped Data object.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsEnvelopedDataParser">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataParser.GetRecipientInfos">
+            return a store of the intended recipients for this message
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataParser.GetUnprotectedAttributes">
+            return a table of the unprotected attributes indexed by
+            the OID of the attribute.
+            @throws IOException
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsEnvelopedDataParser.EncryptionAlgOid">
+            return the object identifier for the content encryption algorithm.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsEnvelopedDataParser.EncryptionAlgParams">
+            return the ASN.1 encoded encryption algorithm parameters, or null if
+            there aren't any.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator">
+             General class for generating a CMS enveloped-data message stream.
+             <p>
+             A simple example of usage.
+             <pre>
+                  CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
+            
+                  edGen.AddKeyTransRecipient(cert);
+            
+                  MemoryStream  bOut = new MemoryStream();
+            
+                  Stream out = edGen.Open(
+                                          bOut, CMSEnvelopedDataGenerator.AES128_CBC);*
+                  out.Write(data);
+            
+                  out.Close();
+             </pre>
+             </p>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Constructor allowing specific source of randomness</summary>
+            <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator.SetBufferSize(System.Int32)">
+            <summary>Set the underlying string size for encapsulated data.</summary>
+            <param name="bufferSize">Length of octet strings to buffer the data.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator.SetBerEncodeRecipients(System.Boolean)">
+            <summary>Use a BER Set to store the recipient information.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator.Open(System.IO.Stream,System.String,Org.BouncyCastle.Crypto.CipherKeyGenerator)">
+            <summary>
+            Generate an enveloped object that contains an CMS Enveloped Data
+            object using the passed in key generator.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator.Open(System.IO.Stream,System.String)">
+            generate an enveloped object that contains an CMS Enveloped Data object
+            @throws IOException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsEnvelopedDataStreamGenerator.Open(System.IO.Stream,System.String,System.Int32)">
+            generate an enveloped object that contains an CMS Enveloped Data object
+            @throws IOException
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.ICipherParameters">
+            all parameter classes implement this.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsProcessable.Write(System.IO.Stream)">
+            <summary>
+            Generic routine to copy out the data we want processed.
+            </summary>
+            <remarks>
+            This routine may be called multiple times.
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsProcessableByteArray">
+            a holding class for a byte array of data to be processed.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsProcessableByteArray.GetContent">
+            <returns>A clone of the byte array</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsSignedData">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.#ctor(System.Collections.IDictionary,System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.#ctor(Org.BouncyCastle.Cms.CmsProcessable,System.IO.Stream)">
+             base constructor - content with detached signature.
+            
+             @param signedContent the content that was signed.
+             @param sigData the signature object.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.#ctor(System.IO.Stream)">
+            base constructor - with encapsulated content
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.GetSignerInfos">
+            return the collection of signers that are associated with the
+            signatures for the message.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.GetAttributeCertificates(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.GetCertificates(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.GetCrls(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.ReplaceSigners(Org.BouncyCastle.Cms.CmsSignedData,Org.BouncyCastle.Cms.SignerInformationStore)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedData.ReplaceCertificatesAndCrls(Org.BouncyCastle.Cms.CmsSignedData,Org.BouncyCastle.X509.Store.IX509Store,Org.BouncyCastle.X509.Store.IX509Store,Org.BouncyCastle.X509.Store.IX509Store)">
+             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
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsSignedData.Version">
+            <summary>Return the version number for this object.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsSignedData.SignedContentType">
+            <summary>
+            Return the <c>DerObjectIdentifier</c> associated with the encapsulated
+            content info structure carried in the signed data.
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsSignedData.ContentInfo">
+            return the ContentInfo
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsSignedDataGenerator">
+                 * general class for generating a pkcs7-signature message.
+                 * <p>
+                 * A simple example of usage.
+                 *
+                 * <pre>
+                 *      IX509Store certs...
+                 *      IX509Store crls...
+                 *      CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+                 *
+                 *      gen.AddSigner(privKey, cert, CmsSignedGenerator.DigestSha1);
+                 *      gen.AddCertificates(certs);
+                 *      gen.AddCrls(crls);
+                 *
+                 *      CmsSignedData data = gen.Generate(content);
+                 * </pre>
+            	 * </p>
+        </member>
+        <member name="F:Org.BouncyCastle.Cms.CmsSignedGenerator.Data">
+            Default type for the signed data.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Constructor allowing specific source of randomness</summary>
+            <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedGenerator.AddAttributeCertificates(Org.BouncyCastle.X509.Store.IX509Store)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedGenerator.AddSigners(Org.BouncyCastle.Cms.SignerInformationStore)">
+             Add a store of precalculated signers to the generator.
+            
+             @param signerStore store of signers
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedGenerator.GetGeneratedDigests">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Constructor allowing specific source of randomness</summary>
+            <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String)">
+                    * add a signer - no attributes other than the default ones will be
+                    * provided here.
+            		*
+            		* @param key signing key to use
+            		* @param cert certificate containing corresponding public key
+            		* @param digestOID digest algorithm OID
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String)">
+             add a signer, specifying the digest encryption algorithm to use - no attributes other than the default ones will be
+             provided here.
+            
+             @param key signing key to use
+             @param cert certificate containing corresponding public key
+             @param encryptionOID digest encryption algorithm OID
+             @param digestOID digest algorithm OID
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String)">
+            add a signer - no attributes other than the default ones will be
+            provided here.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,System.String)">
+            add a signer, specifying the digest encryption algorithm to use - no attributes other than the default ones will be
+            provided here.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+                    * add a signer with extra signed/unsigned attributes.
+            		*
+            		* @param key signing key to use
+            		* @param cert certificate containing corresponding public key
+            		* @param digestOID digest algorithm OID
+            		* @param signedAttr table of attributes to be included in signature
+            		* @param unsignedAttr table of attributes to be included as unsigned
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+             add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes.
+            
+             @param key signing key to use
+             @param cert certificate containing corresponding public key
+             @param encryptionOID digest encryption algorithm OID
+             @param digestOID digest algorithm OID
+             @param signedAttr table of attributes to be included in signature
+             @param unsignedAttr table of attributes to be included as unsigned
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+            	     * add a signer with extra signed/unsigned attributes.
+            		 *
+            		 * @param key signing key to use
+            		 * @param subjectKeyID subjectKeyID of corresponding public key
+            		 * @param digestOID digest algorithm OID
+            		 * @param signedAttr table of attributes to be included in signature
+            		 * @param unsignedAttr table of attributes to be included as unsigned
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+             add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes.
+            
+             @param key signing key to use
+             @param subjectKeyID subjectKeyID of corresponding public key
+             @param encryptionOID digest encryption algorithm OID
+             @param digestOID digest algorithm OID
+             @param signedAttr table of attributes to be included in signature
+             @param unsignedAttr table of attributes to be included as unsigned
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,Org.BouncyCastle.Cms.CmsAttributeTableGenerator,Org.BouncyCastle.Cms.CmsAttributeTableGenerator)">
+            add a signer with extra signed/unsigned attributes based on generators.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String,Org.BouncyCastle.Cms.CmsAttributeTableGenerator,Org.BouncyCastle.Cms.CmsAttributeTableGenerator)">
+            add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes based on generators.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,Org.BouncyCastle.Cms.CmsAttributeTableGenerator,Org.BouncyCastle.Cms.CmsAttributeTableGenerator)">
+            add a signer with extra signed/unsigned attributes based on generators.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,System.String,Org.BouncyCastle.Cms.CmsAttributeTableGenerator,Org.BouncyCastle.Cms.CmsAttributeTableGenerator)">
+            add a signer, including digest encryption algorithm, with extra signed/unsigned attributes based on generators.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable)">
+            generate a signed object that for a CMS Signed Data object
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.Generate(System.String,Org.BouncyCastle.Cms.CmsProcessable,System.Boolean)">
+            generate a signed object that for a CMS Signed Data
+            object  - if encapsulate is true a copy
+            of the message will be included in the signature. The content type
+            is set according to the OID represented by the string signedContentType.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.Generate(Org.BouncyCastle.Cms.CmsProcessable,System.Boolean)">
+            generate a signed object that for a CMS Signed Data
+            object - if encapsulate is true a copy
+            of the message will be included in the signature with the
+            default content type "data".
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataGenerator.GenerateCounterSigners(Org.BouncyCastle.Cms.SignerInformation)">
+             generate a set of one or more SignerInformation objects representing counter signatures on
+             the passed in SignerInformation object.
+            
+             @param signer the signer to be countersigned
+             @param sigProvider the provider to be used for counter signing.
+             @return a store containing the signers.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsSignedDataParser">
+             Parsing class for an CMS Signed Data object from an input stream.
+             <p>
+             Note: that because we are in a streaming mode only one signer can be tried and it is important
+             that the methods on the parser are called in the appropriate order.
+             </p>
+             <p>
+             A simple example of usage for an encapsulated signature.
+             </p>
+             <p>
+             Two notes: first, in the example below the validity of
+             the certificate isn't verified, just the fact that one of the certs
+             matches the given signer, and, second, because we are in a streaming
+             mode the order of the operations is important.
+             </p>
+             <pre>
+                  CmsSignedDataParser     sp = new CmsSignedDataParser(encapSigData);
+            
+                  sp.GetSignedContent().Drain();
+            
+                  IX509Store              certs = sp.GetCertificates();
+                  SignerInformationStore  signers = sp.GetSignerInfos();
+            
+                  foreach (SignerInformation signer in signers.GetSigners())
+                  {
+                      ArrayList       certList = new ArrayList(certs.GetMatches(signer.SignerID));
+                      X509Certificate cert = (X509Certificate) certList[0];
+            
+                      Console.WriteLine("verify returns: " + signer.Verify(cert));
+                  }
+             </pre>
+              Note also: this class does not introduce buffering - if you are processing large files you should create
+              the parser with:
+              <pre>
+                      CmsSignedDataParser     ep = new CmsSignedDataParser(new BufferedInputStream(encapSigData, bufSize));
+              </pre>
+              where bufSize is a suitably large buffer size.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.#ctor(System.IO.Stream)">
+            base constructor - with encapsulated content
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.#ctor(Org.BouncyCastle.Cms.CmsTypedStream,System.IO.Stream)">
+             base constructor
+            
+             @param signedContent the content that was signed.
+             @param sigData the signature object.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.GetSignerInfos">
+            return the collection of signers that are associated with the
+            signatures for the message.
+            @throws CmsException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.GetAttributeCertificates(System.String)">
+             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 org.bouncycastle.x509.NoSuchStoreException if the store type isn't available.
+             @exception CmsException if a general exception prevents creation of the X509Store
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.GetCertificates(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.GetCrls(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.ReplaceSigners(System.IO.Stream,Org.BouncyCastle.Cms.SignerInformationStore,System.IO.Stream)">
+            Replace the signerinformation store associated with the passed
+            in message contained in the stream original 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.
+            <p>
+            The output stream is returned unclosed.
+            </p>
+            @param original the signed data stream to be used as a base.
+            @param signerInformationStore the new signer information store to use.
+            @param out the stream to Write the new signed data object to.
+            @return out.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataParser.ReplaceCertificatesAndCrls(System.IO.Stream,Org.BouncyCastle.X509.Store.IX509Store,Org.BouncyCastle.X509.Store.IX509Store,Org.BouncyCastle.X509.Store.IX509Store,System.IO.Stream)">
+            Replace the certificate and CRL information associated with this
+            CMSSignedData object with the new one passed in.
+            <p>
+            The output stream is returned unclosed.
+            </p>
+            @param original the signed data stream to be used as a base.
+            @param certsAndCrls the new certificates and CRLs to be used.
+            @param out the stream to Write the new signed data object to.
+            @return out.
+            @exception CmsException if there is an error processing the CertStore
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsSignedDataParser.Version">
+             Return the version number for the SignedData object
+            
+             @return the version number
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.CmsSignedDataParser.SignedContentType">
+            <summary>
+            Return the <c>DerObjectIdentifier</c> associated with the encapsulated
+            content info structure carried in the signed data.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator">
+             General class for generating a pkcs7-signature message stream.
+             <p>
+             A simple example of usage.
+             </p>
+             <pre>
+                  IX509Store                   certs...
+                  CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+            
+                  gen.AddSigner(privateKey, cert, CmsSignedDataStreamGenerator.DIGEST_SHA1);
+            
+                  gen.AddCertificates(certs);
+            
+                  Stream sigOut = gen.Open(bOut);
+            
+                  sigOut.Write(Encoding.UTF8.GetBytes("Hello World!"));
+            
+                  sigOut.Close();
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.#ctor(Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Constructor allowing specific source of randomness</summary>
+            <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.SetBufferSize(System.Int32)">
+             Set the underlying string size for encapsulated data
+            
+             @param bufferSize length of octet strings to buffer the data.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String)">
+            add a signer - no attributes other than the default ones will be
+            provided here.
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String)">
+            add a signer, specifying the digest encryption algorithm - no attributes other than the default ones will be
+            provided here.
+            @throws NoSuchProviderException
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+            add a signer with extra signed/unsigned attributes.
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+            add a signer with extra signed/unsigned attributes - specifying digest
+            encryption algorithm.
+            @throws NoSuchProviderException
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String)">
+            add a signer - no attributes other than the default ones will be
+            provided here.
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,System.String)">
+            add a signer - no attributes other than the default ones will be
+            provided here.
+            @throws NoSuchProviderException
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.AddSigner(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[],System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+            add a signer with extra signed/unsigned attributes.
+            @throws NoSuchAlgorithmException
+            @throws InvalidKeyException
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.Open(System.IO.Stream)">
+            generate a signed object that for a CMS Signed Data object
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.Open(System.IO.Stream,System.Boolean)">
+            generate a signed object that for a CMS Signed Data
+            object - if encapsulate is true a copy
+            of the message will be included in the signature with the
+            default content type "data".
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.Open(System.IO.Stream,System.Boolean,System.IO.Stream)">
+            generate a signed object that for a CMS Signed Data
+            object using the given provider - if encapsulate is true a copy
+            of the message will be included in the signature with the
+            default content type "data". If dataOutputStream is non null the data
+            being signed will be written to the stream as it is processed.
+            @param out stream the CMS object is to be written to.
+            @param encapsulate true if data should be encapsulated.
+            @param dataOutputStream output stream to copy the data being signed to.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.Open(System.IO.Stream,System.String,System.Boolean)">
+            generate a signed object that for a CMS Signed Data
+            object - if encapsulate is true a copy
+            of the message will be included in the signature. The content type
+            is set according to the OID represented by the string signedContentType.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedDataStreamGenerator.Open(System.IO.Stream,System.String,System.Boolean,System.IO.Stream)">
+            generate a signed object that for a CMS Signed Data
+            object using the given provider - if encapsulate is true a copy
+            of the message will be included in the signature. The content type
+            is set according to the OID represented by the string signedContentType.
+            @param out stream the CMS object is to be written to.
+            @param signedContentType OID for data to be signed.
+            @param encapsulate true if data should be encapsulated.
+            @param dataOutputStream output stream to copy the data being signed to.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedHelper.GetDigestAlgName(System.String)">
+            Return the digest algorithm using one of the standard JCA string
+            representations rather than the algorithm identifier (if possible).
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.CmsSignedHelper.GetEncryptionAlgName(System.String)">
+            Return the digest encryption algorithm using one of the standard
+            JCA string representations rather than the algorithm identifier (if
+            possible).
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.DefaultAuthenticatedAttributeTableGenerator">
+            Default authenticated attributes generator.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultAuthenticatedAttributeTableGenerator.#ctor">
+            Initialise to use all defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultAuthenticatedAttributeTableGenerator.#ctor(Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+             Initialise with some extra attributes or overrides.
+            
+             @param attributeTable initial attribute table to use.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultAuthenticatedAttributeTableGenerator.CreateStandardAttributeTable(System.Collections.IDictionary)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultAuthenticatedAttributeTableGenerator.GetAttributes(System.Collections.IDictionary)">
+            @param parameters source parameters
+            @return the populated attribute table
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.DefaultSignedAttributeTableGenerator">
+            Default signed attributes generator.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultSignedAttributeTableGenerator.#ctor">
+            Initialise to use all defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultSignedAttributeTableGenerator.#ctor(Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+             Initialise with some extra attributes or overrides.
+            
+             @param attributeTable initial attribute table to use.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultSignedAttributeTableGenerator.createStandardAttributeTable(System.Collections.IDictionary)">
+             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
+             messageDigest will override the generated ones.
+            
+             @param parameters source parameters for table generation.
+            
+             @return a filled in Hashtable of attributes.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.DefaultSignedAttributeTableGenerator.GetAttributes(System.Collections.IDictionary)">
+            @param parameters source parameters
+            @return the populated attribute table
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.RecipientInfoGenerator.Generate(Org.BouncyCastle.Crypto.Parameters.KeyParameter,Org.BouncyCastle.Security.SecureRandom)">
+            <summary>
+            Generate a RecipientInfo object for the given key.
+            </summary>
+            <param name="contentEncryptionKey">
+            A <see cref="T:Org.BouncyCastle.Crypto.Parameters.KeyParameter"/>
+            </param>
+            <param name="random">
+            A <see cref="T:Org.BouncyCastle.Security.SecureRandom"/>
+            </param>
+            <returns>
+            A <see cref="T:Org.BouncyCastle.Asn1.Cms.RecipientInfo"/>
+            </returns>
+            <exception cref="T:Org.BouncyCastle.Security.GeneralSecurityException"></exception>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.KekRecipientInformation">
+            the RecipientInfo class for a recipient who has been sent a message
+            encrypted using a secret key known to the other side.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.RecipientInformation.GetMac">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.RecipientInformation.KeyEncryptionAlgOid">
+                    * return the object identifier for the key encryption algorithm.
+                    * 
+            		* @return OID for key encryption algorithm.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.RecipientInformation.KeyEncryptionAlgParams">
+                    * 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.KekRecipientInformation.GetContentStream(Org.BouncyCastle.Crypto.ICipherParameters)">
+            decrypt the content and return an input stream.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.KeyAgreeRecipientInformation">
+            the RecipientInfo class for a recipient who has been sent a message
+            encrypted using key agreement.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.KeyAgreeRecipientInformation.GetContentStream(Org.BouncyCastle.Crypto.ICipherParameters)">
+            decrypt the content and return an input stream.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.KeyTransRecipientInformation">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.KeyTransRecipientInformation.GetContentStream(Org.BouncyCastle.Crypto.ICipherParameters)">
+            decrypt the content and return it as a byte array.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.OriginatorID">
+            a basic index for an originator.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CertStoreSelector.Policy">
+            <summary>
+            An <code>ISet</code> of <code>DerObjectIdentifier</code> objects.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.PasswordRecipientInformation">
+            the RecipientInfo class for a recipient who has been sent a message
+            encrypted using a password.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.PasswordRecipientInformation.GetContentStream(Org.BouncyCastle.Crypto.ICipherParameters)">
+            decrypt the content and return an input stream.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.PasswordRecipientInformation.KeyDerivationAlgorithm">
+             return the object identifier for the key derivation algorithm, or null
+             if there is none present.
+            
+             @return OID for key derivation algorithm, if present.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.Pkcs5Scheme2PbeKey">
+            <summary>
+            PKCS5 scheme-2 - password converted to bytes assuming ASCII.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.Pkcs5Scheme2Utf8PbeKey">
+            PKCS5 scheme-2 - password converted to bytes using UTF-8.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.RecipientInformationStore.GetFirstRecipient(Org.BouncyCastle.Cms.RecipientID)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.RecipientInformationStore.GetRecipients">
+             Return all recipients in the collection
+            
+             @return a collection of recipients.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.RecipientInformationStore.GetRecipients(Org.BouncyCastle.Cms.RecipientID)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.RecipientInformationStore.Count">
+             Return the number of recipients in the collection.
+            
+             @return number of recipients identified.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.SignerID">
+            a basic index for a signer.
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.SignerInformation">
+            an expanded SignerInfo block from a CMS Signed message
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.GetContentDigest">
+            return the content digest that was calculated during verification.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.GetSignature">
+            return the encoded signature
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.GetCounterSignatures">
+            Return a SignerInformationStore containing the counter signatures attached to this
+            signer. If no counter signatures are present an empty store is returned.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.GetEncodedSignedAttributes">
+            return the DER encoding of the signed attributes.
+            @throws IOException if an encoding error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.Verify(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            verify that the given public key successfully handles and confirms the
+            signature associated with this signer.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.Verify(Org.BouncyCastle.X509.X509Certificate)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.ToSignerInfo">
+             Return the base ASN.1 CMS structure that this object contains.
+            
+             @return an object containing a CMS SignerInfo structure.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.ReplaceUnsignedAttributes(Org.BouncyCastle.Cms.SignerInformation,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformation.AddCounterSigners(Org.BouncyCastle.Cms.SignerInformation,Org.BouncyCastle.Cms.SignerInformationStore)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.Version">
+            return the version number for this objects underlying SignerInfo structure.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.DigestAlgOid">
+            return the object identifier for the signature.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.DigestAlgParams">
+            return the signature parameters, or null if there aren't any.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.EncryptionAlgOid">
+            return the object identifier for the signature.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.EncryptionAlgParams">
+            return the signature/encryption algorithm parameters, or null if
+            there aren't any.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.SignedAttributes">
+            return a table of the signed attributes - indexed by
+            the OID of the attribute.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformation.UnsignedAttributes">
+            return a table of the unsigned attributes indexed by
+            the OID of the attribute.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformationStore.GetFirstSigner(Org.BouncyCastle.Cms.SignerID)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformationStore.GetSigners">
+            <returns>An ICollection of all signers in the collection</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Cms.SignerInformationStore.GetSigners(Org.BouncyCastle.Cms.SignerID)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Cms.SignerInformationStore.Count">
+            <summary>The number of signers in the collection.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Cms.SimpleAttributeTableGenerator">
+            Basic generator that just returns a preconstructed attribute table
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.DHAgreement">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.DHAgreement.CalculateMessage">
+            calculate our initial message.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.DHAgreement.CalculateAgreement(Org.BouncyCastle.Crypto.Parameters.DHPublicKeyParameters,Org.BouncyCastle.Math.BigInteger)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.DHBasicAgreement">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IBasicAgreement">
+            The basic interface that basic Diffie-Hellman implementations
+            conforms to.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBasicAgreement.Init(Org.BouncyCastle.Crypto.ICipherParameters)">
+            initialise the agreement engine.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBasicAgreement.CalculateAgreement(Org.BouncyCastle.Crypto.ICipherParameters)">
+            given a public key from a given party calculate the next
+            message in the agreement sequence.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.DHBasicAgreement.CalculateAgreement(Org.BouncyCastle.Crypto.ICipherParameters)">
+            given a short term public key from a given party calculate the next
+            message in the agreement sequence.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.ECDHBasicAgreement">
+             P1363 7.2.1 ECSVDP-DH
+            
+             ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive,
+             Diffie-Hellman version. It is based on the work of [DH76], [Mil86],
+             and [Kob87]. This primitive derives a shared secret value from one
+             party's private key and another party's public key, where both have
+             the same set of EC domain parameters. If two parties correctly
+             execute this primitive, they will produce the same output. This
+             primitive can be invoked by a scheme to derive a shared secret key;
+             specifically, it may be used with the schemes ECKAS-DH1 and
+             DL/ECKAS-DH2. It assumes that the input keys are valid (see also
+             Section 7.2.2).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.ECDHCBasicAgreement">
+             P1363 7.2.2 ECSVDP-DHC
+            
+             ECSVDP-DHC is Elliptic Curve Secret Value Derivation Primitive,
+             Diffie-Hellman version with cofactor multiplication. It is based on
+             the work of [DH76], [Mil86], [Kob87], [LMQ98] and [Kal98a]. This
+             primitive derives a shared secret value from one party's private key
+             and another party's public key, where both have the same set of EC
+             domain parameters. If two parties correctly execute this primitive,
+             they will produce the same output. This primitive can be invoked by a
+             scheme to derive a shared secret key; specifically, it may be used
+             with the schemes ECKAS-DH1 and DL/ECKAS-DH2. It does not assume the
+             validity of the input public key (see also Section 7.2.1).
+             <p>
+             Note: As stated P1363 compatibility mode with ECDH can be preset, and
+             in this case the implementation doesn't have a ECDH compatibility mode
+             (if you want that just use ECDHBasicAgreement and note they both implement
+             BasicAgreement!).</p>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IDerivationParameters">
+            Parameters for key/byte stream derivation classes
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.Kdf.DHKekGenerator">
+            RFC 2631 Diffie-hellman KEK derivation function.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IDerivationFunction">
+            base interface for general purpose byte derivation functions.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IDerivationFunction.Digest">
+            return the message digest used as the basis for the function
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.Kdf.ECDHKekGenerator">
+            X9.63 based key derivation function for ECDH CMS.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Client">
+            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"
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Client.Init(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Crypto.IDigest,Org.BouncyCastle.Security.SecureRandom)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Client.GenerateClientCredentials(System.Byte[],System.Byte[],System.Byte[])">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Client.CalculateSecret(Org.BouncyCastle.Math.BigInteger)">
+            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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Server">
+            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"
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Server.Init(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Crypto.IDigest,Org.BouncyCastle.Security.SecureRandom)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Server.GenerateServerCredentials">
+            Generates the server's credentials that are to be sent to the client.
+            @return The server's public value to the client
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6Server.CalculateSecret(Org.BouncyCastle.Math.BigInteger)">
+            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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6VerifierGenerator">
+            Generates new SRP verifier for user
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6VerifierGenerator.Init(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Crypto.IDigest)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Agreement.Srp.Srp6VerifierGenerator.GenerateVerifier(System.Byte[],System.Byte[],System.Byte[])">
+            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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair">
+            a holding class for public/private parameter pairs.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+             basic constructor.
+            
+             @param publicParam a public key parameters object.
+             @param privateParam the corresponding private key parameters.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair.Public">
+             return the public key parameters.
+            
+             @return the public key parameters.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair.Private">
+             return the private key parameters.
+            
+             @return the private key parameters.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher">
+            The AEAD block ciphers already handle buffering internally, so this class
+            just takes care of implementing IBufferedCipher methods.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IBufferedCipher">
+            <remarks>Block cipher engines are expected to conform to this interface.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBufferedCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBufferedCipher.Reset">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IBufferedCipher.AlgorithmName">
+            <summary>The name of the algorithm this cipher implements.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.GetBlockSize">
+             return the blocksize for the underlying cipher.
+            
+             @return the blocksize for the underlying cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.GetUpdateOutputSize(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.GetOutputSize(System.Int32)">
+             return the size of the output buffer required for an update plus a
+             doFinal with an input of len bytes.
+            
+             @param len the length of the input.
+             @return the space required to accommodate a call to update and doFinal
+             with len bytes of input.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.DoFinal(System.Byte[],System.Int32)">
+             Process the last block in the buffer.
+            
+             @param out the array the block currently being held is copied into.
+             @param outOff the offset at which the copying starts.
+             @return the number of output bytes copied to out.
+             @exception DataLengthException if there is insufficient space in out for
+             the output, or the input is not block size aligned and should be.
+             @exception InvalidOperationException if the underlying cipher is not
+             initialised.
+             @exception InvalidCipherTextException if padding is expected and not found.
+             @exception DataLengthException if the input is not block size
+             aligned.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAeadBlockCipher.Reset">
+            Reset the buffer and cipher. After resetting the object is in the same
+            state as it was after the last init (if there was one).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher">
+            a buffer wrapper for an asymmetric block cipher, allowing input
+            to be accumulated in a piecemeal fashion until final processing.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher)">
+             base constructor.
+            
+             @param cipher the cipher this buffering object wraps.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher.GetBufferPosition">
+             return the amount of data sitting in the buffer.
+            
+             @return the amount of data sitting in the buffer.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher.DoFinal">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher.Reset">
+            <summary>Reset the buffer</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.BufferedBlockCipher">
+            A wrapper class that allows block ciphers to be used to process data in
+            a piecemeal fashion. The BufferedBlockCipher outputs a block only when the
+            buffer is full and more data is being added, or on a doFinal.
+            <p>
+            Note: in the case where the underlying cipher is either a CFB cipher or an
+            OFB one the last block may not be a multiple of the block size.
+            </p>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.#ctor">
+            constructor for subclasses
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Create a buffered block cipher without padding.
+            
+             @param cipher the underlying block cipher this buffering object wraps.
+             false otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.GetBlockSize">
+             return the blocksize for the underlying cipher.
+            
+             @return the blocksize for the underlying cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.GetUpdateOutputSize(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.GetOutputSize(System.Int32)">
+             return the size of the output buffer required for an update plus a
+             doFinal with an input of len bytes.
+            
+             @param len the length of the input.
+             @return the space required to accommodate a call to update and doFinal
+             with len bytes of input.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.DoFinal(System.Byte[],System.Int32)">
+             Process the last block in the buffer.
+            
+             @param out the array the block currently being held is copied into.
+             @param outOff the offset at which the copying starts.
+             @return the number of output bytes copied to out.
+             @exception DataLengthException if there is insufficient space in out for
+             the output, or the input is not block size aligned and should be.
+             @exception InvalidOperationException if the underlying cipher is not
+             initialised.
+             @exception InvalidCipherTextException if padding is expected and not found.
+             @exception DataLengthException if the input is not block size
+             aligned.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.BufferedBlockCipher.Reset">
+            Reset the buffer and cipher. After resetting the object is in the same
+            state as it was after the last init (if there was one).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.CipherKeyGenerator">
+            The base class for symmetric, or secret, cipher key generators.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.CipherKeyGenerator.Init(Org.BouncyCastle.Crypto.KeyGenerationParameters)">
+             initialise the key generator.
+            
+             @param param the parameters to be used for key generation
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.CipherKeyGenerator.GenerateKey">
+             Generate a secret key.
+            
+             @return a byte array containing the key value.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.DataLengthException">
+            this exception is thrown if a buffer that is meant to have output
+            copied into it turns out to be too short, or if we've been given
+            insufficient input. In general this exception will Get thrown rather
+            than an ArrayOutOfBounds exception.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.DataLengthException.#ctor">
+            base constructor.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.DataLengthException.#ctor(System.String)">
+             create a DataLengthException with the given message.
+            
+             @param message the message to be carried with the exception.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.GeneralDigest">
+            base implementation of MD4 family style digest as outlined in
+            "Handbook of Applied Cryptography", pages 344 - 347.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IDigest">
+            interface that a message digest conforms to.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDigest.GetDigestSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDigest.GetByteLength">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDigest.Update(System.Byte)">
+             update the message digest with a single byte.
+            
+             @param inByte the input byte to be entered.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDigest.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDigest.DoFinal(System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDigest.Reset">
+            reset the digest back to it's initial state.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IDigest.AlgorithmName">
+             return the algorithm name
+            
+             @return the algorithm name
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.Gost3411Digest">
+            implementation of GOST R 34.11-94
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Gost3411Digest.#ctor">
+            Standard constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Gost3411Digest.#ctor(System.Byte[])">
+            Constructor to allow use of a particular sbox with GOST28147
+            @see GOST28147Engine#getSBox(String)
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Gost3411Digest.#ctor(Org.BouncyCastle.Crypto.Digests.Gost3411Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Digests.Gost3411Digest.C2">
+            reset the chaining variables to the IV values.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.LongDigest">
+            Base class for SHA-384 and SHA-512.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.LongDigest.#ctor">
+            Constructor for variable length word
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.LongDigest.#ctor(Org.BouncyCastle.Crypto.Digests.LongDigest)">
+            Copy constructor.  We are using copy constructors in place
+            of the object.Clone() interface as this interface is not
+            supported by J2ME.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.LongDigest.AdjustByteCounts">
+            adjust the byte counts so that byteCount2 represents the
+            upper long (less 3 bits) word of the byte count.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.MD2Digest">
+            implementation of MD2
+            as outlined in RFC1319 by B.Kaliski from RSA Laboratories April 1992
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD2Digest.DoFinal(System.Byte[],System.Int32)">
+             Close the digest, producing the final digest value. The doFinal
+             call leaves the digest reset.
+            
+             @param out the array the digest is to be copied into.
+             @param outOff the offset into the out array the digest is to start at.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD2Digest.Reset">
+            reset the digest back to it's initial state.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD2Digest.Update(System.Byte)">
+             update the message digest with a single byte.
+            
+             @param in the input byte to be entered.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD2Digest.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+             update the message digest with a block of bytes.
+            
+             @param in the byte array containing the data.
+             @param inOff the offset into the byte array where the data starts.
+             @param len the length of the data.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Digests.MD2Digest.AlgorithmName">
+             return the algorithm name
+            
+             @return the algorithm name
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.MD4Digest">
+            implementation of MD4 as RFC 1320 by R. Rivest, MIT Laboratory for
+            Computer Science and RSA Data Security, Inc.
+            <p>
+            <b>NOTE</b>: This algorithm is only included for backwards compatibility
+            with legacy applications, it's not secure, don't use it for anything new!</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD4Digest.#ctor">
+            Standard constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD4Digest.#ctor(Org.BouncyCastle.Crypto.Digests.MD4Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD4Digest.Reset">
+            reset the chaining variables to the IV values.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.MD5Digest">
+            implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD5Digest.#ctor(Org.BouncyCastle.Crypto.Digests.MD5Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.MD5Digest.Reset">
+            reset the chaining variables to the IV values.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.RipeMD128Digest">
+            implementation of RipeMD128
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD128Digest.#ctor">
+            Standard constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD128Digest.#ctor(Org.BouncyCastle.Crypto.Digests.RipeMD128Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD128Digest.Reset">
+            reset the chaining variables to the IV values.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.RipeMD160Digest">
+            implementation of RipeMD see,
+            http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD160Digest.#ctor">
+            Standard constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD160Digest.#ctor(Org.BouncyCastle.Crypto.Digests.RipeMD160Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD160Digest.Reset">
+            reset the chaining variables to the IV values.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.RipeMD256Digest">
+            <remarks>
+            <p>Implementation of RipeMD256.</p>
+            <p><b>Note:</b> this algorithm offers the same level of security as RipeMD128.</p>
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD256Digest.#ctor">
+            <summary> Standard constructor</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD256Digest.#ctor(Org.BouncyCastle.Crypto.Digests.RipeMD256Digest)">
+            <summary> Copy constructor.  This will copy the state of the provided
+            message digest.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD256Digest.Reset">
+            <summary> reset the chaining variables to the IV values.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.RipeMD320Digest">
+            <remarks>
+            <p>Implementation of RipeMD 320.</p>
+            <p><b>Note:</b> this algorithm offers the same level of security as RipeMD160.</p>
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD320Digest.#ctor">
+            <summary> Standard constructor</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD320Digest.#ctor(Org.BouncyCastle.Crypto.Digests.RipeMD320Digest)">
+            <summary> Copy constructor.  This will copy the state of the provided
+            message digest.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.RipeMD320Digest.Reset">
+            <summary> reset the chaining variables to the IV values.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.Sha1Digest">
+             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!
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha1Digest.#ctor(Org.BouncyCastle.Crypto.Digests.Sha1Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha1Digest.Reset">
+            reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.Sha224Digest">
+            SHA-224 as described in RFC 3874
+            <pre>
+                    block  word  digest
+            SHA-1   512    32    160
+            SHA-224 512    32    224
+            SHA-256 512    32    256
+            SHA-384 1024   64    384
+            SHA-512 1024   64    512
+            </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha224Digest.#ctor">
+            Standard constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha224Digest.#ctor(Org.BouncyCastle.Crypto.Digests.Sha224Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha224Digest.Reset">
+            reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.Sha256Digest">
+             Draft FIPS 180-2 implementation of SHA-256. <b>Note:</b> As this is
+             based on a draft this implementation is subject to change.
+            
+             <pre>
+                     block  word  digest
+             SHA-1   512    32    160
+             SHA-256 512    32    256
+             SHA-384 1024   64    384
+             SHA-512 1024   64    512
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha256Digest.#ctor(Org.BouncyCastle.Crypto.Digests.Sha256Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha256Digest.Reset">
+            reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.Sha384Digest">
+             Draft FIPS 180-2 implementation of SHA-384. <b>Note:</b> As this is
+             based on a draft this implementation is subject to change.
+            
+             <pre>
+                     block  word  digest
+             SHA-1   512    32    160
+             SHA-256 512    32    256
+             SHA-384 1024   64    384
+             SHA-512 1024   64    512
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha384Digest.#ctor(Org.BouncyCastle.Crypto.Digests.Sha384Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha384Digest.Reset">
+            reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.Sha512Digest">
+             Draft FIPS 180-2 implementation of SHA-512. <b>Note:</b> As this is
+             based on a draft this implementation is subject to change.
+            
+             <pre>
+                     block  word  digest
+             SHA-1   512    32    160
+             SHA-256 512    32    256
+             SHA-384 1024   64    384
+             SHA-512 1024   64    512
+             </pre>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha512Digest.#ctor(Org.BouncyCastle.Crypto.Digests.Sha512Digest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.Sha512Digest.Reset">
+            reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.ShortenedDigest">
+            Wrapper class that reduces the output length of a particular digest to
+            only the first n bytes of the digest function.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.ShortenedDigest.#ctor(Org.BouncyCastle.Crypto.IDigest,System.Int32)">
+             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().
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.TigerDigest">
+            implementation of Tiger based on:
+            <a href="http://www.cs.technion.ac.il/~biham/Reports/Tiger">
+             http://www.cs.technion.ac.il/~biham/Reports/Tiger</a>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.TigerDigest.#ctor">
+            Standard constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.TigerDigest.#ctor(Org.BouncyCastle.Crypto.Digests.TigerDigest)">
+            Copy constructor.  This will copy the state of the provided
+            message digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.TigerDigest.Reset">
+            reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Digests.WhirlpoolDigest">
+             Implementation of WhirlpoolDigest, based on Java source published by Barreto
+             and Rijmen.
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.WhirlpoolDigest.#ctor(Org.BouncyCastle.Crypto.Digests.WhirlpoolDigest)">
+            Copy constructor. This will copy the state of the provided message
+            digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Digests.WhirlpoolDigest.Reset">
+            Reset the chaining variables
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Encodings.ISO9796d1Encoding">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IAsymmetricBlockCipher">
+            <remarks>Base interface for a public/private key block cipher.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IAsymmetricBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IAsymmetricBlockCipher.GetInputBlockSize">
+            <returns>The maximum size, in bytes, an input block may be.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IAsymmetricBlockCipher.GetOutputBlockSize">
+            <returns>The maximum size, in bytes, an output block will be.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IAsymmetricBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Int32)">
+            <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="T:Org.BouncyCastle.Crypto.InvalidCipherTextException">Input decrypts improperly.</exception>
+            <exception cref="T:Org.BouncyCastle.Crypto.DataLengthException">Input is too large for the cipher.</exception>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IAsymmetricBlockCipher.AlgorithmName">
+            <summary>The name of the algorithm this cipher implements.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.ISO9796d1Encoding.GetInputBlockSize">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.ISO9796d1Encoding.GetOutputBlockSize">
+            return the maximum possible size for the output.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.ISO9796d1Encoding.SetPadBits(System.Int32)">
+            set the number of bits in the next message to be treated as
+            pad bits.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.ISO9796d1Encoding.GetPadBits">
+            retrieve the number of pad bits in the last decoded message.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.ISO9796d1Encoding.DecodeBlock(System.Byte[],System.Int32,System.Int32)">
+            @exception InvalidCipherTextException if the decrypted block is not a valid ISO 9796 bit string
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Encodings.OaepEncoding">
+            Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.OaepEncoding.decodeBlock(System.Byte[],System.Int32,System.Int32)">
+            @exception InvalidCipherTextException if the decrypted block turns out to
+            be badly formatted.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.OaepEncoding.ItoOSP(System.Int32,System.Byte[])">
+            int to octet string.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.OaepEncoding.maskGeneratorFunction1(System.Byte[],System.Int32,System.Int32,System.Int32)">
+            mask generator function, as described in PKCS1v2.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.StrictLengthEnabledProperty">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher)">
+            Basic constructor.
+            @param cipher
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.DecodeBlock(System.Byte[],System.Int32,System.Int32)">
+            @exception InvalidCipherTextException if the decrypted block is not in Pkcs1 format.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.StrictLengthEnabled">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.AesEngine">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IBlockCipher">
+            <remarks>Base interface for a symmetric key block cipher.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBlockCipher.GetBlockSize">
+            <returns>The block size for this cipher, in bytes.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+            <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="T:Org.BouncyCastle.Crypto.DataLengthException">If input block is wrong size, or outBuf too small.</exception>
+            <returns>The number of bytes processed and produced.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IBlockCipher.Reset">
+            <summary>
+            Reset the cipher to the same state as it was after the last init (if there was one).
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IBlockCipher.AlgorithmName">
+            <summary>The name of the algorithm this cipher implements.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IBlockCipher.IsPartialBlockOkay">
+            <summary>Indicates whether this cipher can handle partial blocks.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesEngine.GenerateWorkingKey(System.Byte[],System.Boolean)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesEngine.#ctor">
+            default constructor - 128 bit block size.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.AesFastEngine">
+             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 fast version with 8Kbytes of static tables for round precomputation
+             </p>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesFastEngine.GenerateWorkingKey(System.Byte[],System.Boolean)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesFastEngine.#ctor">
+            default constructor - 128 bit block size.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesFastEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.AesLightEngine">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesLightEngine.GenerateWorkingKey(System.Byte[],System.Boolean)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesLightEngine.#ctor">
+            default constructor - 128 bit block size.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.AesLightEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.AesWrapEngine">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.Rfc3394WrapEngine">
+            <remarks>
+            An implementation of the AES Key Wrapper from the NIST Key Wrap
+            Specification as described in RFC 3394.
+            <p/>
+            For further details see: <a href="http://www.ietf.org/rfc/rfc3394.txt">http://www.ietf.org/rfc/rfc3394.txt</a>
+            and  <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
+            </remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IWrapper.AlgorithmName">
+            <summary>The name of the algorithm this cipher implements.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.BlowfishEngine">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.BlowfishEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.BlowfishEngine.ProcessTable(System.UInt32,System.UInt32,System.UInt32[])">
+            apply the encryption cycle to each value pair in the table.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.BlowfishEngine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.BlowfishEngine.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.CamelliaEngine">
+            Camellia - based on RFC 3713.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.CamelliaLightEngine">
+            Camellia - based on RFC 3713, smaller implementation, about half the size of CamelliaEngine.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.CamelliaWrapEngine">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.Cast5Engine">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.F1(System.UInt32,System.UInt32,System.Int32)">
+             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
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.F2(System.UInt32,System.UInt32,System.Int32)">
+             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
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.F3(System.UInt32,System.UInt32,System.Int32)">
+             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
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast5Engine.CAST_Encipher(System.UInt32,System.UInt32,System.UInt32[])">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.Cast6Engine">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast6Engine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast6Engine.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast6Engine.CAST_Encipher(System.UInt32,System.UInt32,System.UInt32,System.UInt32,System.UInt32[])">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Cast6Engine.CAST_Decipher(System.UInt32,System.UInt32,System.UInt32,System.UInt32,System.UInt32[])">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.DesEdeEngine">
+            <remarks>A class that provides a basic DESede (or Triple DES) engine.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.DesEngine">
+            <remarks>A class that provides a basic DES engine.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEngine.bytebit">
+            what follows is mainly taken from "Applied Cryptography", by
+            Bruce Schneier, however it also bears great resemblance to Richard
+            Outerbridge's D3DES...
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEngine.GenerateWorkingKey(System.Boolean,System.Byte[])">
+             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!).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEngine.DesFunc(System.Int32[],System.Byte[],System.Int32,System.Byte[],System.Int32)">
+            the DES engine.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEdeEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine">
+                * 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>
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.engine">
+            Field engine 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.param">
+            Field param 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.paramPlusIV">
+            Field paramPlusIV 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.iv">
+            Field iv 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.forWrapping">
+            Field forWrapping 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.IV2">
+            Field IV2           
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Method init
+            
+             @param forWrapping
+             @param param
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.Wrap(System.Byte[],System.Int32,System.Int32)">
+             Method wrap
+            
+             @param in
+             @param inOff
+             @param inLen
+             @return
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.Unwrap(System.Byte[],System.Int32,System.Int32)">
+             Method unwrap
+            
+             @param in
+             @param inOff
+             @param inLen
+             @return
+             @throws InvalidCipherTextException
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.CalculateCmsKeyChecksum(System.Byte[])">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.CheckCmsKeyChecksum(System.Byte[],System.Byte[])">
+            @param key
+            @param checksum
+            @return
+            @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Engines.DesEdeWrapEngine.AlgorithmName">
+             Method GetAlgorithmName
+            
+             @return
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.ElGamalEngine">
+            this does your basic ElGamal algorithm.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.ElGamalEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             initialise the ElGamal engine.
+            
+             @param forEncryption true if we are encrypting, false otherwise.
+             @param param the necessary ElGamal key parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.ElGamalEngine.GetInputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.ElGamalEngine.GetOutputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.ElGamalEngine.ProcessBlock(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.Gost28147Engine">
+            implementation of GOST 28147-89
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Gost28147Engine.#ctor">
+            standard constructor.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Gost28147Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             initialise an Gost28147 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Gost28147Engine.GetSBox(System.String)">
+            Return the S-Box associated with SBoxName
+            @param sBoxName name of the S-Box
+            @return byte array representing the S-Box
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.HC128Engine">
+             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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IStreamCipher">
+            <summary>The interface stream ciphers conform to.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IStreamCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            <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="T:System.ArgumentException">
+            If the parameters argument is inappropriate.
+            </exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IStreamCipher.ReturnByte(System.Byte)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IStreamCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+            <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="T:Org.BouncyCastle.Crypto.DataLengthException">If the output buffer is too small.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IStreamCipher.Reset">
+            <summary>
+            Reset the cipher to the same state as it was after the last init (if there was one).
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IStreamCipher.AlgorithmName">
+            <summary>The name of the algorithm this cipher implements.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.HC128Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.HC256Engine">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.HC256Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.IesEngine">
+            support class for constructing intergrated encryption ciphers
+            for doing basic message exchanges on top of key agreement ciphers
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.IesEngine.#ctor(Org.BouncyCastle.Crypto.IBasicAgreement,Org.BouncyCastle.Crypto.IDerivationFunction,Org.BouncyCastle.Crypto.IMac)">
+             set up for use with stream mode, where the key derivation function
+             is used to provide a stream of bytes to xor with the message.
+            
+             @param agree the key agreement used as the basis for the encryption
+             @param kdf the key derivation function used for byte generation
+             @param mac the message authentication code generator for the message
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.IesEngine.#ctor(Org.BouncyCastle.Crypto.IBasicAgreement,Org.BouncyCastle.Crypto.IDerivationFunction,Org.BouncyCastle.Crypto.IMac,Org.BouncyCastle.Crypto.BufferedBlockCipher)">
+             set up for use in conjunction with a block cipher to handle the
+             message.
+            
+             @param agree the key agreement used as the basis for the encryption
+             @param kdf the key derivation function used for byte generation
+             @param mac the message authentication code generator for the message
+             @param cipher the cipher to used for encrypting the message
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.IesEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters,Org.BouncyCastle.Crypto.ICipherParameters,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the encryptor.
+            
+             @param forEncryption whether or not this is encryption/decryption.
+             @param privParam our private key parameters
+             @param pubParam the recipient's/sender's public key parameters
+             @param param encoding and derivation parameters.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.IsaacEngine">
+            Implementation of Bob Jenkin's ISAAC (Indirection Shift Accumulate Add and Count).
+            see: http://www.burtleburtle.net/bob/rand/isaacafa.html
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.IsaacEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine">
+            NaccacheStern Engine. For details on this cipher, please see
+            http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initializes this algorithm. Must be called before all other Functions.
+            
+             @see org.bouncycastle.crypto.AsymmetricBlockCipher#init(bool,
+                  org.bouncycastle.crypto.CipherParameters)
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.GetInputBlockSize">
+             Returns the input block size of this algorithm.
+            
+             @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetInputBlockSize()
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.GetOutputBlockSize">
+             Returns the output block size of this algorithm.
+            
+             @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetOutputBlockSize()
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.ProcessBlock(System.Byte[],System.Int32,System.Int32)">
+             Process a single Block using the Naccache-Stern algorithm.
+            
+             @see org.bouncycastle.crypto.AsymmetricBlockCipher#ProcessBlock(byte[],
+                  int, int)
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.Encrypt(Org.BouncyCastle.Math.BigInteger)">
+             Encrypts a BigInteger aka Plaintext with the public key.
+            
+             @param plain
+                        The BigInteger to encrypt
+             @return The byte[] representation of the encrypted BigInteger (i.e.
+                     crypted.toByteArray())
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.AddCryptedBlocks(System.Byte[],System.Byte[])">
+             Adds the contents of two encrypted blocks mod sigma
+            
+             @param block1
+                        the first encrypted block
+             @param block2
+                        the second encrypted block
+             @return encrypt((block1 + block2) mod sigma)
+             @throws InvalidCipherTextException
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.ProcessData(System.Byte[])">
+             Convenience Method for data exchange with the cipher.
+            
+             Determines blocksize and splits data to blocksize.
+            
+             @param data the data to be processed
+             @return the data after it went through the NaccacheSternEngine.
+             @throws InvalidCipherTextException
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NaccacheSternEngine.chineseRemainder(System.Collections.IList,System.Collections.IList)">
+             Computes the integer x that is expressed through the given primes and the
+             congruences with the chinese remainder theorem (CRT).
+            
+             @param congruences
+                        the congruences c_i
+             @param primes
+                        the primes p_i
+             @return an integer x for that x % p_i == c_i
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.NoekeonEngine">
+            A Noekeon engine, using direct-key mode.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NoekeonEngine.#ctor">
+            Create an instance of the Noekeon encryption algorithm
+            and set some defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NoekeonEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.NoekeonEngine.setKey(System.Byte[])">
+             Re-key the cipher.
+            
+             @param  key  the key to be used
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.NullEngine">
+            The no-op engine that just copies bytes through, irrespective of whether encrypting and decrypting.
+            Provided for the sake of completeness.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RC2Engine">
+            an implementation of RC2 as described in RFC 2268
+                 "A Description of the RC2(r) Encryption Algorithm" R. Rivest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2Engine.RotateWordLeft(System.Int32,System.Int32)">
+            return the result rotating the 16 bit number in x left by y
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine">
+            Wrap keys according to RFC 3217 - RC2 mechanism
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.engine">
+            Field engine 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.parameters">
+            Field param 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.paramPlusIV">
+            Field paramPlusIV 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.iv">
+            Field iv 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.forWrapping">
+            Field forWrapping 
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.IV2">
+            Field IV2           
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Method init
+            
+             @param forWrapping
+             @param param
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.Wrap(System.Byte[],System.Int32,System.Int32)">
+             Method wrap
+            
+             @param in
+             @param inOff
+             @param inLen
+             @return
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.Unwrap(System.Byte[],System.Int32,System.Int32)">
+             Method unwrap
+            
+             @param in
+             @param inOff
+             @param inLen
+             @return
+             @throws InvalidCipherTextException
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.CalculateCmsKeyChecksum(System.Byte[])">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.CheckCmsKeyChecksum(System.Byte[],System.Byte[])">
+            @param key
+            @param checksum
+            @return
+            @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Engines.RC2WrapEngine.AlgorithmName">
+             Method GetAlgorithmName
+            
+             @return
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC4Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RC532Engine">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC532Engine.#ctor">
+            Create an instance of the RC5 encryption algorithm
+            and set some defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC532Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC532Engine.SetKey(System.Byte[])">
+             Re-key the cipher.
+            
+             @param  key  the key to be used
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC532Engine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC532Engine.RotateLeft(System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC532Engine.RotateRight(System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RC564Engine">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC564Engine.#ctor">
+            Create an instance of the RC5 encryption algorithm
+            and set some defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC564Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC564Engine.SetKey(System.Byte[])">
+             Re-key the cipher.
+            
+             @param  key  the key to be used
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC564Engine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC564Engine.RotateLeft(System.Int64,System.Int64)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC564Engine.RotateRight(System.Int64,System.Int64)">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RC6Engine">
+            An RC6 engine.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC6Engine.#ctor">
+            Create an instance of the RC6 encryption algorithm
+            and set some defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC6Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC6Engine.SetKey(System.Byte[])">
+             Re-key the cipher.
+            
+             @param inKey the key to be used
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC6Engine.RotateLeft(System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RC6Engine.RotateRight(System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.Rfc3211WrapEngine">
+            an implementation of the RFC 3211 Key Wrap
+            Specification.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RijndaelEngine">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.Mul0x2(System.Int32)">
+            multiply two elements of GF(2^m)
+            needed for MixColumn and InvMixColumn
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.KeyAddition(System.Int64[])">
+            xor corresponding text input and round key input bytes
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.ShiftRow(System.Byte[])">
+            Row 0 remains unchanged
+            The other three rows are shifted a variable amount
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.Substitution(System.Byte[])">
+            Replace every byte of the input by the byte at that place
+            in the nonlinear S-box
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.MixColumn">
+            Mix the bytes of every column in a linear way
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.InvMixColumn">
+            Mix the bytes of every column in a linear way
+            This is the opposite operation of Mixcolumn
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.GenerateWorkingKey(System.Byte[])">
+            Calculate the necessary round keys
+            The number of calculations depends on keyBits and blockBits
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.#ctor">
+            default constructor - 128 bit block size.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.#ctor(System.Int32)">
+             basic constructor - set the cipher up for a given blocksize
+            
+             @param blocksize the blocksize in bits, must be 128, 192, or 256.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RijndaelEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine">
+            this does your basic RSA algorithm with blinding
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             initialise the RSA engine.
+            
+             @param forEncryption true if we are encrypting, false otherwise.
+             @param param the necessary RSA key parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine.GetInputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine.GetOutputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine.ProcessBlock(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RsaBlindingEngine">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindingEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the blinding engine.
+            
+             @param forEncryption true if we are encrypting (blinding), false otherwise.
+             @param param         the necessary RSA key parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindingEngine.GetInputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindingEngine.GetOutputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaBlindingEngine.ProcessBlock(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RsaCoreEngine">
+            this does your basic RSA algorithm.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaCoreEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             initialise the RSA engine.
+            
+             @param forEncryption true if we are encrypting, false otherwise.
+             @param param the necessary RSA key parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaCoreEngine.GetInputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaCoreEngine.GetOutputBlockSize">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.RsaEngine">
+            this does your basic RSA algorithm.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             initialise the RSA engine.
+            
+             @param forEncryption true if we are encrypting, false otherwise.
+             @param param the necessary RSA key parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaEngine.GetInputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaEngine.GetOutputBlockSize">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.RsaEngine.ProcessBlock(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.Salsa20Engine">
+            Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.Salsa20Engine.StateSize">
+            Constants 
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.Salsa20Engine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.SeedEngine">
+            Implementation of the SEED algorithm as described in RFC 4009
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.SeedWrapEngine">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.SerpentEngine">
+                * 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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.MakeWorkingKey(System.Byte[])">
+             Expand a user-supplied key material into a session key.
+            
+             @param key  The user-key bytes (multiples of 4) to use.
+             @exception ArgumentException
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb0(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib0(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvSO - {13, 3,11, 0,10, 6, 5,12, 1,14, 4, 7,15, 9, 8, 2 } - 15 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb1(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S1 - {15,12, 2, 7, 9, 0, 5,10, 1,11,14, 8, 6,13, 3, 4 } - 14 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib1(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS1 - { 5, 8, 2,14,15, 6,12, 3,11, 4, 7, 9, 1,13,10, 0 } - 14 steps.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb2(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S2 - { 8, 6, 7, 9, 3,12,10,15,13, 1,14, 4, 0,11, 5, 2 } - 16 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib2(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS2 - {12, 9,15, 4,11,14, 1, 2, 0, 3, 6,13, 5, 8,10, 7 } - 16 steps.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb3(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S3 - { 0,15,11, 8,12, 9, 6, 3,13, 1, 2, 4,10, 7, 5,14 } - 16 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib3(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb4(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S4 - { 1,15, 8, 3,12, 0,11, 6, 2, 5, 4,10, 9,14, 7,13 } - 15 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib4(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS4 - { 5, 0, 8, 3,10, 9, 7,14, 2,12,11, 6, 4,15,13, 1 } - 15 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb5(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S5 - {15, 5, 2,11, 4,10, 9,12, 0, 3,14, 8,13, 6, 7, 1 } - 16 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib5(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS5 - { 8,15, 2, 9, 4, 1,13,14,11, 6, 5, 3, 7,12,10, 0 } - 16 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb6(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S6 - { 7, 2,12, 5, 8, 4, 6,11,14, 9, 1,15,13, 3,10, 0 } - 15 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib6(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS6 - {15,10, 1,13, 5, 3, 6, 0, 4, 9,14, 7, 2,12, 8,11 } - 15 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Sb7(System.Int32,System.Int32,System.Int32,System.Int32)">
+            S7 - { 1,13,15, 0,14, 8, 2,11, 7, 4,12,10, 9, 3, 5, 6 } - 16 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.Ib7(System.Int32,System.Int32,System.Int32,System.Int32)">
+            InvS7 - { 3, 0, 6,13, 9,14,15, 8, 5,12,11, 7,10, 1, 4, 2 } - 17 terms.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.LT">
+            Apply the linear transformation to the register set.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SerpentEngine.InverseLT">
+            Apply the inverse of the linear transformation to the register set.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.SkipjackEngine">
+            a class that provides a basic SKIPJACK engine.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SkipjackEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SkipjackEngine.G(System.Int32,System.Int32)">
+            The G permutation
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.SkipjackEngine.H(System.Int32,System.Int32)">
+            the inverse of the G permutation.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.TeaEngine">
+            An TEA engine.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TeaEngine.#ctor">
+            Create an instance of the TEA encryption algorithm
+            and set some defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TeaEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TeaEngine.setKey(System.Byte[])">
+             Re-key the cipher.
+            
+             @param  key  the key to be used
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.TwofishEngine">
+             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.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.TwofishEngine.P_00">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Engines.TwofishEngine.gSubKeys">
+            gSubKeys[] and gSBox[] are eventually used in the
+            encryption and decryption methods.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TwofishEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TwofishEngine.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TwofishEngine.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TwofishEngine.RS_MDS_Encode(System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.TwofishEngine.RS_rem(System.Int32)">
+                    * 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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.VmpcEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Engines.XteaEngine">
+            An XTEA engine.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.XteaEngine.#ctor">
+            Create an instance of the TEA encryption algorithm
+            and set some defaults
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.XteaEngine.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Engines.XteaEngine.setKey(System.Byte[])">
+             Re-key the cipher.
+            
+             @param  key  the key to be used
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.BaseKdfBytesGenerator">
+            Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+            <br/>
+            This implementation is based on ISO 18033/P1363a.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.BaseKdfBytesGenerator.#ctor(System.Int32,Org.BouncyCastle.Crypto.IDigest)">
+             Construct a KDF Parameters generator.
+            
+             @param counterStart value of counter.
+             @param digest the digest to be used as the source of derived keys.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.BaseKdfBytesGenerator.GenerateBytes(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Generators.BaseKdfBytesGenerator.Digest">
+            return the underlying digest.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.DesKeyGenerator.engineInit(Org.BouncyCastle.Crypto.KeyGenerationParameters)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.DesEdeKeyGenerator.engineInit(Org.BouncyCastle.Crypto.KeyGenerationParameters)">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.DHBasicKeyPairGenerator">
+             a basic Diffie-Hellman key pair generator.
+            
+             This generates keys consistent for use with the basic algorithm for
+             Diffie-Hellman.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IAsymmetricCipherKeyPairGenerator">
+            interface that a public/private key pair generator should conform to.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IAsymmetricCipherKeyPairGenerator.Init(Org.BouncyCastle.Crypto.KeyGenerationParameters)">
+             intialise the key pair generator.
+            
+             @param the parameters the key pair is to be initialised with.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IAsymmetricCipherKeyPairGenerator.GenerateKeyPair">
+             return an AsymmetricCipherKeyPair containing the Generated keys.
+            
+             @return an AsymmetricCipherKeyPair containing the Generated keys.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.DHKeyPairGenerator">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.DHParametersGenerator.GenerateParameters">
+            which Generates the p and g values from the given parameters,
+            returning the DHParameters object.
+            <p>
+            Note: can take a while...</p>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.DsaKeyPairGenerator">
+                 * 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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.DsaParametersGenerator">
+            Generate suitable parameters for DSA, in line with FIPS 186-2.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.DsaParametersGenerator.Init(System.Int32,System.Int32,Org.BouncyCastle.Security.SecureRandom)">
+             initialise the key generator.
+            
+             @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments)
+             @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
+             @param random random byte source.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.DsaParametersGenerator.GenerateParameters">
+            which Generates the p and g values from the given parameters,
+            returning the DsaParameters object.
+            <p>
+            Note: can take a while...</p>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.DsaParametersGenerator.GenerateParameters_FIPS186_3">
+            generate suitable parameters for DSA, in line with
+            <i>FIPS 186-3 A.1 Generation of the FFC Primes p and q</i>.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator.GenerateKeyPair">
+            Given the domain parameters this routine Generates an EC key
+            pair in accordance with X9.62 section 5.2.1 pages 26, 27.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.ElGamalKeyPairGenerator">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.ElGamalParametersGenerator.GenerateParameters">
+                     * which Generates the p and g values from the given parameters,
+                     * returning the ElGamalParameters object.
+                     * <p>
+                     * Note: can take a while...
+            		 * </p>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Gost3410KeyPairGenerator">
+            a GOST3410 key pair generator.
+            This generates GOST3410 keys in line with the method described
+            in GOST R 34.10-94.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Gost3410ParametersGenerator">
+            generate suitable parameters for GOST3410.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Gost3410ParametersGenerator.Init(System.Int32,System.Int32,Org.BouncyCastle.Security.SecureRandom)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Gost3410ParametersGenerator.procedure_C(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            Procedure C
+            procedure generates the a value from the given p,q,
+            returning the a value.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Gost3410ParametersGenerator.GenerateParameters">
+            which generates the p , q and a values from the given parameters,
+            returning the Gost3410Parameters object.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Kdf1BytesGenerator">
+            KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+            <br/>
+            This implementation is based on IEEE P1363/ISO 18033.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Kdf1BytesGenerator.#ctor(Org.BouncyCastle.Crypto.IDigest)">
+             Construct a KDF1 byte generator.
+            
+             @param digest the digest to be used as the source of derived keys.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Kdf2BytesGenerator">
+            KDF2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+            <br/>
+            This implementation is based on IEEE P1363/ISO 18033.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Kdf2BytesGenerator.#ctor(Org.BouncyCastle.Crypto.IDigest)">
+             Construct a KDF2 bytes generator. Generates key material
+             according to IEEE P1363 or ISO 18033 depending on the initialisation.
+            
+             @param digest the digest to be used as the source of derived keys.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Mgf1BytesGenerator">
+            Generator for MGF1 as defined in Pkcs 1v2
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Mgf1BytesGenerator.#ctor(Org.BouncyCastle.Crypto.IDigest)">
+            @param digest the digest to be used as the source of Generated bytes
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Mgf1BytesGenerator.ItoOSP(System.Int32,System.Byte[])">
+            int to octet string.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Mgf1BytesGenerator.GenerateBytes(System.Byte[],System.Int32,System.Int32)">
+             fill len bytes of the output buffer with bytes Generated from
+             the derivation function.
+            
+             @throws DataLengthException if the out buffer is too small.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Generators.Mgf1BytesGenerator.Digest">
+            return the underlying digest.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.NaccacheSternKeyPairGenerator">
+             Key generation parameters for NaccacheStern cipher. For details on this cipher, please see
+            
+             http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.NaccacheSternKeyPairGenerator.permuteList(System.Collections.IList,Org.BouncyCastle.Security.SecureRandom)">
+             Generates a permuted ArrayList from the original one. The original List
+             is not modified
+            
+             @param arr
+                        the ArrayList to be permuted
+             @param rand
+                        the source of Randomness for permutation
+             @return a new ArrayList with the permuted elements.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.NaccacheSternKeyPairGenerator.findFirstPrimes(System.Int32)">
+             Finds the first 'count' primes starting with 3
+            
+             @param count
+                        the number of primes to find
+             @return a vector containing the found primes as Integer
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.PbeParametersGenerator">
+            super class for all Password Based Encyrption (Pbe) parameter generator classes.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.#ctor">
+            base constructor.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.Init(System.Byte[],System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.GetPassword">
+             return the password byte array.
+            
+             @return the password byte array.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.GetSalt">
+             return the salt byte array.
+            
+             @return the salt byte array.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.GenerateDerivedParameters(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.GenerateDerivedParameters(System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.GenerateDerivedMacParameters(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.Pkcs5PasswordToBytes(System.Char[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.Pkcs5PasswordToUtf8Bytes(System.Char[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.PbeParametersGenerator.Pkcs12PasswordToBytes(System.Char[])">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.PbeParametersGenerator.IterationCount">
+             return the iteration count.
+            
+             @return the iteration count.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator.#ctor">
+            Construct a OpenSSL Parameters generator. 
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator.Init(System.Byte[],System.Byte[])">
+            Initialise - note the iteration count for this algorithm is fixed at 1.
+            
+            @param password password to use.
+            @param salt salt to use.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator.GenerateDerivedKey(System.Int32)">
+            the derived key function, the ith hash of the password and the salt.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator.GenerateDerivedParameters(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator.GenerateDerivedParameters(System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.OpenSslPbeParametersGenerator.GenerateDerivedMacParameters(System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator.#ctor(Org.BouncyCastle.Crypto.IDigest)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator.Adjust(System.Byte[],System.Int32,System.Byte[])">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator.GenerateDerivedKey(System.Int32,System.Int32)">
+            generation of a derived key ala Pkcs12 V1.0.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator.GenerateDerivedParameters(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator.GenerateDerivedParameters(System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs12ParametersGenerator.GenerateDerivedMacParameters(System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Pkcs5S1ParametersGenerator">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S1ParametersGenerator.#ctor(Org.BouncyCastle.Crypto.IDigest)">
+             Construct a Pkcs 5 Scheme 1 Parameters generator.
+            
+             @param digest the digest to be used as the source of derived keys.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S1ParametersGenerator.GenerateDerivedKey">
+            the derived key function, the ith hash of the mPassword and the mSalt.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S1ParametersGenerator.GenerateDerivedParameters(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S1ParametersGenerator.GenerateDerivedParameters(System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S1ParametersGenerator.GenerateDerivedMacParameters(System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator.#ctor">
+            construct a Pkcs5 Scheme 2 Parameters generator.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator.GenerateDerivedParameters(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator.GenerateDerivedParameters(System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.Pkcs5S2ParametersGenerator.GenerateDerivedMacParameters(System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.RsaBlindingFactorGenerator">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.RsaBlindingFactorGenerator.Init(Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the factor generator
+            
+             @param param the necessary RSA key parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Generators.RsaBlindingFactorGenerator.GenerateBlindingFactor">
+             Generate a suitable blind factor for the public key the generator was initialised with.
+            
+             @return a random blind factor
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Generators.RsaKeyPairGenerator">
+            an RSA key pair generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IDsa">
+            interface for classes implementing the Digital Signature Algorithm
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDsa.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDsa.GenerateSignature(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IDsa.VerifySignature(System.Byte[],Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.IMac">
+            The base interface for implementations of message authentication codes (MACs).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IMac.Init(Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the MAC.
+            
+             @param param the key and other data required by the MAC.
+             @exception ArgumentException if the parameters argument is
+             inappropriate.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IMac.GetMacSize">
+             Return the block size for this MAC (in bytes).
+            
+             @return the block size for this MAC in bytes.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IMac.Update(System.Byte)">
+             add a single byte to the mac for processing.
+            
+             @param in the byte to be processed.
+             @exception InvalidOperationException if the MAC is not initialised.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IMac.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            @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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IMac.DoFinal(System.Byte[],System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.IMac.Reset">
+            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).
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.IMac.AlgorithmName">
+             Return the name of the algorithm the MAC implements.
+            
+             @return the name of the algorithm the MAC implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.InvalidCipherTextException">
+            this exception is thrown whenever we find something we don't expect in a
+            message.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.InvalidCipherTextException.#ctor">
+            base constructor.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.InvalidCipherTextException.#ctor(System.String)">
+             create a InvalidCipherTextException with the given message.
+            
+             @param message the message to be carried with the exception.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISigner.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the signer for signing or verification.
+            
+             @param forSigning true if for signing, false otherwise
+             @param param necessary parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISigner.Update(System.Byte)">
+            update the internal digest with the byte b
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            update the internal digest with the byte array in
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISigner.GenerateSignature">
+            Generate a signature for the message we've been loaded with using
+            the key we were initialised with.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISigner.VerifySignature(System.Byte[])">
+            return true if the internal state represents the signature described
+            in the passed in array.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISigner.Reset">
+            reset the internal state
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.ISigner.AlgorithmName">
+             Return the name of the algorithm the signer implements.
+            
+             @return the name of the algorithm the signer implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.ISignerWithRecovery">
+            Signer with message recovery.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.HasFullMessage">
+             Returns true if the signer has recovered the full message as
+             part of signature verification.
+            
+             @return true if full message recovered.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.GetRecoveredMessage">
+             Returns a reference to what message was recovered (if any).
+            
+             @return full/partial message, null if nothing.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.UpdateWithRecoveredMessage(System.Byte[])">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.KeyGenerationParameters">
+            The base class for parameters to key generators.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.KeyGenerationParameters.#ctor(Org.BouncyCastle.Security.SecureRandom,System.Int32)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.KeyGenerationParameters.Random">
+             return the random source associated with this
+             generator.
+            
+             @return the generators random source.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.KeyGenerationParameters.Strength">
+             return the bit strength for keys produced by this generator,
+            
+             @return the strength of the keys this generator produces (in bits).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Macs.CbcBlockCipherMac">
+            standard CBC Block Cipher MAC - if no padding is specified the default of
+            pad of zeroes is used.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CbcBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CbcBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CbcBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CbcBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CbcBlockCipherMac.Reset">
+            Reset the mac generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher">
+            implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32)">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher.GetBlockSize">
+             return the block size we are operating at.
+            
+             @return the block size we are operating at (in bytes).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher.Reset">
+            reset the chaining vector back to the IV and reset the underlying
+            cipher.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Macs.MacCFBBlockCipher.AlgorithmName">
+             return the algorithm name and mode.
+            
+             @return the name of the underlying algorithm followed by "/CFB"
+             and the block size in bits.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CfbBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CfbBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CfbBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32,System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CfbBlockCipherMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32,System.Int32,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CfbBlockCipherMac.Reset">
+            Reset the mac generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Macs.CMac">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CMac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.CMac.Reset">
+            Reset the mac generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Macs.Gost28147Mac">
+            implementation of GOST 28147-89 MAC
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Macs.HMac">
+             HMAC implementation based on RFC2104
+            
+             H(K XOR opad, H(K XOR ipad, text))
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.HMac.Reset">
+            Reset the mac generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Macs.ISO9797Alg3Mac">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.ISO9797Alg3Mac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.ISO9797Alg3Mac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.ISO9797Alg3Mac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.ISO9797Alg3Mac.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Macs.ISO9797Alg3Mac.Reset">
+            Reset the mac generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.MaxBytesExceededException">
+            <summary>
+            This exception is thrown whenever a cipher requires a change of key, iv
+            or similar after x amount of bytes enciphered
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher">
+            implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Basic constructor.
+            
+             @param cipher the block cipher to be used as the basis of chaining.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the cipher and, possibly, the initialisation vector (IV).
+             If an IV isn't passed as part of the parameter, the IV will be all zeros.
+            
+             @param 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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.GetBlockSize">
+             return the block size of the underlying cipher.
+            
+             @return the block size of the underlying cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.Reset">
+            reset the chaining vector back to the IV and reset the underlying
+            cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             Do the appropriate chaining step for CBC mode encryption.
+            
+             @param in the array containing the data to be encrypted.
+             @param inOff offset into the in array the data starts at.
+             @param out the array the encrypted data will be copied into.
+             @param outOff the offset into the out array the output will start at.
+             @exception DataLengthException if there isn't enough data in in, or
+             space in out.
+             @exception InvalidOperationException if the cipher isn't initialised.
+             @return the number of bytes processed and produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             Do the appropriate chaining step for CBC mode decryption.
+            
+             @param in the array containing the data to be decrypted.
+             @param inOff offset into the in array the data starts at.
+             @param out the array the decrypted data will be copied into.
+             @param outOff the offset into the out array the output will start at.
+             @exception DataLengthException if there isn't enough data in in, or
+             space in out.
+             @exception InvalidOperationException if the cipher isn't initialised.
+             @return the number of bytes processed and produced.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Modes.CbcBlockCipher.AlgorithmName">
+             return the algorithm name and mode.
+            
+             @return the name of the underlying algorithm followed by "/CBC".
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.CcmBlockCipher">
+                * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
+                * NIST Special Publication 800-38C.
+                * <p>
+                * <b>Note</b>: this mode is a packet mode - it needs all the data up front.
+            	* </p>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher">
+            <summary>
+            A block cipher mode that includes authenticated encryption with a streaming mode
+            and optional associated data.</summary>
+            <see cref="T:Org.BouncyCastle.Crypto.Parameters.AeadParameters"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            <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>
+            <param name="parameters">The key or other data required by the cipher.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.GetBlockSize">
+            <returns>The block size for this cipher, in bytes.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+             Encrypt/decrypt a single byte.
+            
+             @param input the byte to be processed.
+             @param outBytes the output buffer the processed byte goes into.
+             @param outOff the offset into the output byte array the processed data starts at.
+             @return the number of bytes written to out.
+             @exception DataLengthException if the output buffer is too small.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+             Process a block of bytes from in putting the result into out.
+            
+             @param inBytes 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 outBytes the output buffer the processed bytes go into.
+             @param outOff the offset into the output byte array the processed data starts at.
+             @return the number of bytes written to out.
+             @exception DataLengthException if the output buffer is too small.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.DoFinal(System.Byte[],System.Int32)">
+             Finish the operation either appending or verifying the MAC at the end of the data.
+            
+             @param outBytes space for any resulting output data.
+             @param outOff offset into out to start copying the data at.
+             @return number of bytes written into out.
+             @throws InvalidOperationException if the cipher is in an inappropriate state.
+             @throws InvalidCipherTextException if the MAC fails to match.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.GetMac">
+             Return the value of the MAC associated with the last stream processed.
+            
+             @return MAC for plaintext data.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.GetUpdateOutputSize(System.Int32)">
+             Return the size of the output buffer required for a ProcessBytes
+             an input of len bytes.
+            
+             @param len the length of the input.
+             @return the space required to accommodate a call to ProcessBytes
+             with len bytes of input.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.GetOutputSize(System.Int32)">
+             Return the size of the output buffer required for a ProcessBytes plus a
+             DoFinal with an input of len bytes.
+            
+             @param len the length of the input.
+             @return the space required to accommodate a call to ProcessBytes and DoFinal
+             with len bytes of input.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.Reset">
+            <summary>
+            Reset the cipher to the same state as it was after the last init (if there was one).
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Modes.IAeadBlockCipher.AlgorithmName">
+            <summary>The name of the algorithm this cipher implements.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CcmBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Basic constructor.
+            
+             @param cipher the block cipher to be used.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CcmBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CcmBlockCipher.GetMac">
+             Returns a byte array containing the mac calculated as part of the
+             last encrypt or decrypt operation.
+            
+             @return the last mac calculated.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher">
+            implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32)">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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 param the key and other data required by the cipher.
+             @exception ArgumentException if the parameters argument is
+             inappropriate.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.GetBlockSize">
+             return the block size we are operating at.
+            
+             @return the block size we are operating at (in bytes).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             Do the appropriate processing for CFB mode encryption.
+            
+             @param in the array containing the data to be encrypted.
+             @param inOff offset into the in array the data starts at.
+             @param out the array the encrypted data will be copied into.
+             @param outOff the offset into the out array the output will start at.
+             @exception DataLengthException if there isn't enough data in in, or
+             space in out.
+             @exception InvalidOperationException if the cipher isn't initialised.
+             @return the number of bytes processed and produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             Do the appropriate processing for CFB mode decryption.
+            
+             @param in the array containing the data to be decrypted.
+             @param inOff offset into the in array the data starts at.
+             @param out the array the encrypted data will be copied into.
+             @param outOff the offset into the out array the output will start at.
+             @exception DataLengthException if there isn't enough data in in, or
+             space in out.
+             @exception InvalidOperationException if the cipher isn't initialised.
+             @return the number of bytes processed and produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.Reset">
+            reset the chaining vector back to the IV and reset the underlying
+            cipher.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Modes.CfbBlockCipher.AlgorithmName">
+             return the algorithm name and mode.
+            
+             @return the name of the underlying algorithm followed by "/CFB"
+             and the block size in bits.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Create a buffered block cipher that uses Cipher Text Stealing
+            
+             @param cipher the underlying block cipher this buffering object wraps.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher.GetUpdateOutputSize(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher.GetOutputSize(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.CtsBlockCipher.DoFinal(System.Byte[],System.Int32)">
+             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).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.EaxBlockCipher">
+            A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and 
+            Efficiency - by M. Bellare, P. Rogaway, D. Wagner.
+            
+            http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
+            
+            EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block 
+            cipher to encrypt and authenticate data. It's on-line (the length of a 
+            message isn't needed to begin processing it), has good performances, it's
+            simple and provably secure (provided the underlying block cipher is secure).
+            
+            Of course, this implementations is NOT thread-safe.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.EaxBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Constructor that accepts an instance of a block cipher engine.
+            
+             @param cipher the engine to use
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.GcmBlockCipher">
+            <summary>
+            Implements the Galois/Counter mode (GCM) detailed in
+            NIST Special Publication 800-38D.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher">
+            implements the GOST 28147 OFB counter mode (GCTR).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Basic constructor.
+            
+             @param cipher the block cipher to be used as the basis of the
+             counter mode (must have a 64 bit block size).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the cipher and, possibly, the initialisation vector (IV).
+             If an IV isn't passed as part of the parameter, the IV will be all zeros.
+             An IV which is too short is handled in FIPS compliant fashion.
+            
+             @param encrypting if true the cipher is initialised for
+              encryption, if false for decryption.
+             @param parameters the key and other data required by the cipher.
+             @exception ArgumentException if the parameters argument is inappropriate.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.GetBlockSize">
+             return the block size we are operating at (in bytes).
+            
+             @return the block size we are operating at (in bytes).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.Reset">
+            reset the feedback vector back to the IV and reset the underlying
+            cipher.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Modes.GOfbBlockCipher.AlgorithmName">
+             return the algorithm name and mode.
+            
+             @return the name of the underlying algorithm followed by "/GCTR"
+             and the block size in bits
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher">
+            implements a Output-FeedBack (OFB) mode on top of a simple cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,System.Int32)">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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 param the key and other data required by the cipher.
+             @exception ArgumentException if the parameters argument is
+             inappropriate.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.GetBlockSize">
+             return the block size we are operating at (in bytes).
+            
+             @return the block size we are operating at (in bytes).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.Reset">
+            reset the feedback vector back to the IV and reset the underlying
+            cipher.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Modes.OfbBlockCipher.AlgorithmName">
+             return the algorithm name and mode.
+            
+             @return the name of the underlying algorithm followed by "/OFB"
+             and the block size in bits
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher">
+                * 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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Basic constructor.
+            
+             @param cipher the block cipher to be used as the basis of the
+             feedback mode.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.GetBlockSize">
+             return the block size we are operating at.
+            
+             @return the block size we are operating at (in bytes).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.ProcessBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.Reset">
+            reset the chaining vector back to the IV and reset the underlying
+            cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.EncryptByte(System.Byte,System.Int32)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.EncryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.DecryptBlock(System.Byte[],System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Modes.OpenPgpCfbBlockCipher.AlgorithmName">
+             return the algorithm name and mode.
+            
+             @return the name of the underlying algorithm followed by "/PGPCFB"
+             and the block size in bits.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Modes.SicBlockCipher">
+            Implements the Segmented Integer Counter (SIC) mode on top of a simple
+            block cipher.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.SicBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Basic constructor.
+            
+             @param c the block cipher to be used.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Modes.SicBlockCipher.GetUnderlyingCipher">
+             return the underlying block cipher that we are wrapping.
+            
+             @return the underlying block cipher that we are wrapping.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding">
+            Block cipher padders are expected to conform to this interface
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding.Init(Org.BouncyCastle.Security.SecureRandom)">
+             Initialise the padder.
+            
+             @param param parameters, if any required.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding.AddPadding(System.Byte[],System.Int32)">
+            add the pad bytes to the passed in block, returning the
+            number of bytes added.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding.PadCount(System.Byte[])">
+            return the number of pad bytes present in the block.
+            @exception InvalidCipherTextException if the padding is badly formed
+            or invalid.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding.PaddingName">
+             Return the name of the algorithm the cipher implements.
+            
+             @return the name of the algorithm the cipher implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.ISO10126d2Padding">
+            A padder that adds ISO10126-2 padding to a block.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ISO10126d2Padding.Init(Org.BouncyCastle.Security.SecureRandom)">
+             Initialise the padder.
+            
+             @param random a SecureRandom if available.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ISO10126d2Padding.AddPadding(System.Byte[],System.Int32)">
+            add the pad bytes to the passed in block, returning the
+            number of bytes added.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ISO10126d2Padding.PadCount(System.Byte[])">
+            return the number of pad bytes present in the block.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.ISO10126d2Padding.PaddingName">
+             Return the name of the algorithm the cipher implements.
+            
+             @return the name of the algorithm the cipher implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.ISO7816d4Padding">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ISO7816d4Padding.Init(Org.BouncyCastle.Security.SecureRandom)">
+             Initialise the padder.
+            
+             @param random - a SecureRandom if available.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ISO7816d4Padding.AddPadding(System.Byte[],System.Int32)">
+            add the pad bytes to the passed in block, returning the
+            number of bytes added.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ISO7816d4Padding.PadCount(System.Byte[])">
+            return the number of pad bytes present in the block.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.ISO7816d4Padding.PaddingName">
+             Return the name of the algorithm the padder implements.
+            
+             @return the name of the algorithm the padder implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher,Org.BouncyCastle.Crypto.Paddings.IBlockCipherPadding)">
+             Create a buffered block cipher with the desired padding.
+            
+             @param cipher the underlying block cipher this buffering object wraps.
+             @param padding the padding type.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             Create a buffered block cipher Pkcs7 padding
+            
+             @param cipher the underlying block cipher this buffering object wraps.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.GetOutputSize(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.GetUpdateOutputSize(System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.PaddedBufferedBlockCipher.DoFinal(System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.Pkcs7Padding">
+            A padder that adds Pkcs7/Pkcs5 padding to a block.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.Pkcs7Padding.Init(Org.BouncyCastle.Security.SecureRandom)">
+             Initialise the padder.
+            
+             @param random - a SecureRandom if available.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.Pkcs7Padding.AddPadding(System.Byte[],System.Int32)">
+            add the pad bytes to the passed in block, returning the
+            number of bytes added.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.Pkcs7Padding.PadCount(System.Byte[])">
+            return the number of pad bytes present in the block.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.Pkcs7Padding.PaddingName">
+             Return the name of the algorithm the cipher implements.
+            
+             @return the name of the algorithm the cipher implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.TbcPadding">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.TbcPadding.Init(Org.BouncyCastle.Security.SecureRandom)">
+            <summary> Initialise the padder.</summary>
+            <param name="random">- a SecureRandom if available.
+            </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.TbcPadding.AddPadding(System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.TbcPadding.PadCount(System.Byte[])">
+            <summary> return the number of pad bytes present in the block.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.TbcPadding.PaddingName">
+            <summary> Return the name of the algorithm the cipher implements.</summary>
+            <returns> the name of the algorithm the cipher implements.
+            </returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.X923Padding">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.X923Padding.Init(Org.BouncyCastle.Security.SecureRandom)">
+             Initialise the padder.
+            
+             @param random a SecureRandom if one is available.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.X923Padding.AddPadding(System.Byte[],System.Int32)">
+            add the pad bytes to the passed in block, returning the
+            number of bytes added.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.X923Padding.PadCount(System.Byte[])">
+            return the number of pad bytes present in the block.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.X923Padding.PaddingName">
+             Return the name of the algorithm the cipher implements.
+            
+             @return the name of the algorithm the cipher implements.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Paddings.ZeroBytePadding">
+            <summary> A padder that adds Null byte padding to a block.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ZeroBytePadding.Init(Org.BouncyCastle.Security.SecureRandom)">
+             <summary> Initialise the padder.
+            
+             </summary>
+             <param name="random">- a SecureRandom if available.
+             </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ZeroBytePadding.AddPadding(System.Byte[],System.Int32)">
+            <summary> add the pad bytes to the passed in block, returning the
+            number of bytes added.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Paddings.ZeroBytePadding.PadCount(System.Byte[])">
+            <summary> return the number of pad bytes present in the block.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Paddings.ZeroBytePadding.PaddingName">
+             <summary> Return the name of the algorithm the cipher implements.
+            
+             </summary>
+             <returns> the name of the algorithm the cipher implements.
+             </returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.AeadParameters.#ctor(Org.BouncyCastle.Crypto.Parameters.KeyParameter,System.Int32,System.Byte[],System.Byte[])">
+             Base constructor.
+            
+             @param key key to be used by underlying cipher
+             @param macSize macSize in bits
+             @param nonce nonce to be used
+             @param associatedText associated text, if any
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.CcmParameters.#ctor(Org.BouncyCastle.Crypto.Parameters.KeyParameter,System.Int32,System.Byte[],System.Byte[])">
+            Base constructor.
+            
+            @param key key to be used by underlying cipher
+            @param macSize macSize in bits
+            @param nonce nonce to be used
+            @param associatedText associated text, if any
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.DesParameters.IsWeakKey(System.Byte[],System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.DesParameters.SetOddParity(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.DesEdeParameters.IsWeakKey(System.Byte[],System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.DesEdeParameters.IsWeakKey(System.Byte[],System.Int32)">
+             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
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.DHParameters.M">
+            <summary>The minimum bitlength of the private value.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.DHParameters.L">
+            <summary>The bitlength of the private value.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.ElGamalParameters.G">
+            return the generator - g
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.ElGamalParameters.L">
+            return private value limit - l
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.IesParameters">
+            parameters for using an integrated cipher in stream mode.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.IesParameters.#ctor(System.Byte[],System.Byte[],System.Int32)">
+            @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).
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.IesWithCipherParameters.#ctor(System.Byte[],System.Byte[],System.Int32,System.Int32)">
+            @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).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.Iso18033KdfParameters">
+            parameters for Key derivation functions for ISO-18033
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.KdfParameters">
+            parameters for Key derivation functions for IEEE P1363a
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.MgfParameters">
+            <remarks>Parameters for mask derivation functions.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyGenerationParameters">
+             Parameters for NaccacheStern public private key generation. For details on
+             this cipher, please see
+            
+             http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyGenerationParameters.#ctor(Org.BouncyCastle.Security.SecureRandom,System.Int32,System.Int32,System.Int32)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyGenerationParameters.#ctor(Org.BouncyCastle.Security.SecureRandom,System.Int32,System.Int32,System.Int32,System.Boolean)">
+             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)
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyGenerationParameters.Certainty">
+            @return Returns the certainty.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyGenerationParameters.CountSmallPrimes">
+            @return Returns the countSmallPrimes.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyParameters">
+             Public key parameters for NaccacheStern cipher. For details on this cipher,
+             please see
+            
+             http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyParameters.#ctor(System.Boolean,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,System.Int32)">
+            @param privateKey
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyParameters.G">
+            @return Returns the g.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyParameters.LowerSigmaBound">
+            @return Returns the lowerSigmaBound.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Parameters.NaccacheSternKeyParameters.Modulus">
+            @return Returns the n.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.NaccacheSternPrivateKeyParameters">
+             Private key parameters for NaccacheStern cipher. For details on this cipher,
+             please see
+            
+             http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Parameters.NaccacheSternPrivateKeyParameters.#ctor(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,System.Int32,System.Collections.IList,Org.BouncyCastle.Math.BigInteger)">
+             Constructs a NaccacheSternPrivateKey
+            
+             @param g
+                        the public enryption parameter g
+             @param n
+                        the public modulus n = p*q
+             @param lowerSigmaBound
+                        the public lower sigma bound up to which data can be encrypted
+             @param smallPrimes
+                        the small primes, of which sigma is constructed in the right
+                        order
+             @param phi_n
+                        the private modulus phi(n) = (p-1)(q-1)
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Parameters.ParametersWithSalt">
+            <summary> Cipher parameters with a fixed salt value associated with them.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Prng.DigestRandomGenerator">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Prng.IRandomGenerator">
+            <remarks>Generic interface for objects generating random bytes.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.IRandomGenerator.AddSeedMaterial(System.Byte[])">
+            <summary>Add more seed material to the generator.</summary>
+            <param name="seed">A byte array to be mixed into the generator's state.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.IRandomGenerator.AddSeedMaterial(System.Int64)">
+            <summary>Add more seed material to the generator.</summary>
+            <param name="seed">A long value to be mixed into the generator's state.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.IRandomGenerator.NextBytes(System.Byte[])">
+            <summary>Fill byte array with random values.</summary>
+            <param name="bytes">Array to be filled.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.IRandomGenerator.NextBytes(System.Byte[],System.Int32,System.Int32)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Prng.ReversedWindowGenerator">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.ReversedWindowGenerator.AddSeedMaterial(System.Byte[])">
+            <summary>Add more seed material to the generator.</summary>
+            <param name="seed">A byte array to be mixed into the generator's state.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.ReversedWindowGenerator.AddSeedMaterial(System.Int64)">
+            <summary>Add more seed material to the generator.</summary>
+            <param name="seed">A long value to be mixed into the generator's state.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.ReversedWindowGenerator.NextBytes(System.Byte[])">
+            <summary>Fill byte array with random values.</summary>
+            <param name="bytes">Array to be filled.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.ReversedWindowGenerator.NextBytes(System.Byte[],System.Int32,System.Int32)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Prng.ThreadedSeedGenerator">
+            A thread based seed generator - one source of randomness.
+            <p>
+            Based on an idea from Marcus Lippert.
+            </p>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Prng.ThreadedSeedGenerator.GenerateSeed(System.Int32,System.Boolean)">
+            Generate seed bytes. Set fast to false for best quality.
+            <p>
+            If fast is set to true, the code should be round about 8 times faster when
+            generating a long sequence of random bytes. 20 bytes of random values using
+            the fast mode take less than half a second on a Nokia e70. If fast is set to false,
+            it takes round about 2500 ms.
+            </p>
+            @param numBytes the number of bytes to generate
+            @param fast true if fast mode should be used
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Prng.VmpcRandomGenerator.P">
+            <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>
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Prng.VmpcRandomGenerator.s">
+            <remarks>Value generated in the same way as <c>P</c>.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaDigestSigner.Update(System.Byte)">
+            update the internal digest with the byte b
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaDigestSigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            update the internal digest with the byte array in
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaDigestSigner.GenerateSignature">
+            Generate a signature for the message we've been loaded with using
+            the key we were initialised with.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaDigestSigner.VerifySignature(System.Byte[])">
+            <returns>true if the internal state represents the signature described in the passed in array.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaDigestSigner.Reset">
+            <summary>Reset the internal state</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.DsaSigner">
+            The Digital Signature Algorithm - as described in "Handbook of Applied
+            Cryptography", pages 452 - 453.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaSigner.GenerateSignature(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.DsaSigner.VerifySignature(System.Byte[],Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.ECDsaSigner">
+            EC-DSA as described in X9.62
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.ECDsaSigner.GenerateSignature(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.ECDsaSigner.VerifySignature(System.Byte[],Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.ECGost3410Signer">
+            GOST R 34.10-2001 Signature Algorithm
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.ECGost3410Signer.GenerateSignature(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.ECGost3410Signer.VerifySignature(System.Byte[],Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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).
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.ECNRSigner">
+            EC-NR as described in IEEE 1363-2000
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.ECNRSigner.GenerateSignature(System.Byte[])">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.ECNRSigner.VerifySignature(System.Byte[],Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.GenericSigner.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             initialise the signer for signing or verification.
+            
+             @param forSigning
+                        true if for signing, false otherwise
+             @param parameters
+                        necessary parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.GenericSigner.Update(System.Byte)">
+            update the internal digest with the byte b
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.GenericSigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            update the internal digest with the byte array in
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.GenericSigner.GenerateSignature">
+            Generate a signature for the message we've been loaded with using the key
+            we were initialised with.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.GenericSigner.VerifySignature(System.Byte[])">
+            return true if the internal state represents the signature described in
+            the passed in array.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410DigestSigner.Update(System.Byte)">
+            update the internal digest with the byte b
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410DigestSigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            update the internal digest with the byte array in
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410DigestSigner.GenerateSignature">
+            Generate a signature for the message we've been loaded with using
+            the key we were initialised with.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410DigestSigner.VerifySignature(System.Byte[])">
+            <returns>true if the internal state represents the signature described in the passed in array.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410DigestSigner.Reset">
+            <summary>Reset the internal state</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.Gost3410Signer">
+            Gost R 34.10-94 Signature Algorithm
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410Signer.GenerateSignature(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Gost3410Signer.VerifySignature(System.Byte[],Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.GetRecoveredMessage">
+            <summary>
+            Return a reference to the recoveredMessage message.
+            </summary>
+            <returns>The full/partial recoveredMessage message.</returns>
+            <seealso cref="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.GetRecoveredMessage"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher,Org.BouncyCastle.Crypto.IDigest,System.Int32,System.Boolean)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher,Org.BouncyCastle.Crypto.IDigest,System.Int32)">
+             <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+            <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="T:System.ArgumentException">if wrong parameter type or a fixed
+            salt is passed in which is the wrong length.
+            </exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.IsSameAs(System.Byte[],System.Byte[])">
+            <summary> compare two byte arrays - constant time.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.ClearBlock(System.Byte[])">
+            <summary> clear possible sensitive data</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.Update(System.Byte)">
+            <summary> update the internal digest with the byte b</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            <summary> update the internal digest with the byte array in</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.Reset">
+            <summary> reset the internal state</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.GenerateSignature">
+            <summary> Generate a signature for the loaded message using the key we were
+            initialised with.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.VerifySignature(System.Byte[])">
+            <summary> return true if the signature represents a ISO9796-2 signature
+            for the passed in message.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.HasFullMessage">
+            <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="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.HasFullMessage"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.ItoOSP(System.Int32,System.Byte[])">
+            <summary> int to octet string.</summary>
+            <summary> int to octet string.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.LtoOSP(System.Int64,System.Byte[])">
+            <summary> long to octet string.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2PssSigner.MaskGeneratorFunction1(System.Byte[],System.Int32,System.Int32,System.Int32)">
+            <summary> mask generator function, as described in Pkcs1v2.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer">
+            <summary> ISO9796-2 - mechanism using a hash function with recovery (scheme 1)</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.GetRecoveredMessage">
+            <summary>
+            Return a reference to the recoveredMessage message.
+            </summary>
+            <returns>The full/partial recoveredMessage message.</returns>
+            <seealso cref="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.GetRecoveredMessage"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher,Org.BouncyCastle.Crypto.IDigest,System.Boolean)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher,Org.BouncyCastle.Crypto.IDigest)">
+             <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.IsSameAs(System.Byte[],System.Byte[])">
+            <summary> compare two byte arrays - constant time.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.ClearBlock(System.Byte[])">
+            <summary> clear possible sensitive data</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.Update(System.Byte)">
+            <summary> update the internal digest with the byte b</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            <summary> update the internal digest with the byte array in</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.Reset">
+            <summary> reset the internal state</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.GenerateSignature">
+            <summary> Generate a signature for the loaded message using the key we were
+            initialised with.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.VerifySignature(System.Byte[])">
+            <summary> return true if the signature represents a ISO9796-2 signature
+            for the passed in message.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.Iso9796d2Signer.HasFullMessage">
+            <summary>
+            Return true if the full message was recoveredMessage.
+            </summary>
+            <returns> true on full message recovery, false otherwise.</returns>
+            <seealso cref="M:Org.BouncyCastle.Crypto.ISignerWithRecovery.HasFullMessage"/>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Signers.PssSigner">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.#ctor(Org.BouncyCastle.Crypto.IAsymmetricBlockCipher,Org.BouncyCastle.Crypto.IDigest,System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.ClearBlock(System.Byte[])">
+            <summary> clear possible sensitive data</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.Update(System.Byte)">
+            <summary> update the internal digest with the byte b</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            <summary> update the internal digest with the byte array in</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.Reset">
+            <summary> reset the internal state</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.GenerateSignature">
+            <summary> Generate a signature for the message we've been loaded with using
+            the key we were initialised with.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.VerifySignature(System.Byte[])">
+            <summary> return true if the internal state represents the signature described
+            in the passed in array.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.ItoOSP(System.Int32,System.Byte[])">
+            <summary> int to octet string.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.PssSigner.MaskGeneratorFunction1(System.Byte[],System.Int32,System.Int32,System.Int32)">
+            <summary> mask generator function, as described in Pkcs1v2.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.RsaDigestSigner.#cctor">
+            <summary>
+            Load oid table.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.RsaDigestSigner.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             Initialise the signer for signing or verification.
+            
+             @param forSigning true if for signing, false otherwise
+             @param param necessary parameters.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.RsaDigestSigner.Update(System.Byte)">
+            update the internal digest with the byte b
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.RsaDigestSigner.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            update the internal digest with the byte array in
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.RsaDigestSigner.GenerateSignature">
+            Generate a signature for the message we've been loaded with using
+            the key we were initialised with.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Signers.RsaDigestSigner.VerifySignature(System.Byte[])">
+            return true if the internal state represents the signature described
+            in the passed in array.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.StreamBlockCipher">
+            a wrapper for block ciphers with a single byte block size, so that they
+            can be treated like stream ciphers.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.StreamBlockCipher.#ctor(Org.BouncyCastle.Crypto.IBlockCipher)">
+             basic constructor.
+            
+             @param cipher the block cipher to be wrapped.
+             @exception ArgumentException if the cipher has a block size other than
+             one.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.StreamBlockCipher.Init(System.Boolean,Org.BouncyCastle.Crypto.ICipherParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.StreamBlockCipher.ReturnByte(System.Byte)">
+             encrypt/decrypt a single byte returning the result.
+            
+             @param in the byte to be processed.
+             @return the result of processing the input byte.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.StreamBlockCipher.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.StreamBlockCipher.Reset">
+            reset the underlying cipher. This leaves it in the same state
+            it was at after the last init (if there was one).
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.StreamBlockCipher.AlgorithmName">
+             return the name of the algorithm we are wrapping.
+            
+             @return the name of the algorithm we are wrapping.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.AlertDescription">
+            <summary>
+            RFC 2246 7.2
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.AlertLevel">
+            <summary>
+            RFC 2246 7.2
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.AlwaysValidVerifyer">
+            <remarks>
+            A certificate verifyer, that will always return true.
+            <pre>
+            DO NOT USE THIS FILE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING.
+            </pre>
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ICertificateVerifyer">
+            <remarks>
+            This should be implemented by any class which can find out, if a given
+            certificate chain is being accepted by an client.
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.ICertificateVerifyer.IsValid(Org.BouncyCastle.Asn1.X509.X509CertificateStructure[])">
+            <param name="certs">The certs, which are part of the chain.</param>
+            <returns>True, if the chain is accepted, false otherwise</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.AlwaysValidVerifyer.IsValid(Org.BouncyCastle.Asn1.X509.X509CertificateStructure[])">
+            <summary>Return true.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ByteQueue">
+            <remarks>
+            A queue for bytes.
+            <p>
+            This file could be more optimized.
+            </p>
+            </remarks>
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ByteQueue.InitBufSize">
+            The initial size for our buffer.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.ByteQueue.NextTwoPow(System.Int32)">
+            <returns>The smallest number which can be written as 2^x which is bigger than i.</returns>
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ByteQueue.databuf">
+            The buffer where we store our data.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ByteQueue.skipped">
+            How many bytes at the beginning of the buffer are skipped.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ByteQueue.available">
+            How many bytes in the buffer are valid data.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.ByteQueue.Read(System.Byte[],System.Int32,System.Int32,System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.ByteQueue.AddData(System.Byte[],System.Int32,System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.ByteQueue.RemoveData(System.Int32)">
+            <summary>Remove some bytes from our data from the beginning.</summary>
+            <param name="i">How many bytes to remove.</param>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.ByteQueue.Available">
+            <summary>The number of bytes which are available in this buffer.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.Certificate">
+            A representation for a certificate chain.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.Certificate.certs">
+            The certificates.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.Certificate.Parse(System.IO.Stream)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.Certificate.Encode(System.IO.Stream)">
+             Encodes version of the ClientCertificate message
+            
+             @param outStr stream to write the message to
+             @throws IOException If something goes wrong
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.Certificate.#ctor(Org.BouncyCastle.Asn1.X509.X509CertificateStructure[])">
+             Private constructor from a cert array.
+            
+             @param certs The certs the chain should contain.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.Certificate.GetCerts">
+            <returns>An array which contains the certs, this chain contains.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.CertificateRequest.CertificateAuthorities">
+            <returns>A <see cref="T:System.Collections.IList"/> of X509Name</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.CipherSuite">
+            <summary>
+            RFC 2246 A.5
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ClientCertificateType">
+            <summary>
+            RFC 2246 7.4.4
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.CombinedHash">
+            <remarks>A combined hash, which implements md5(m) || sha1(m).</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.CombinedHash.GetByteLength">
+            <seealso cref="M:Org.BouncyCastle.Crypto.IDigest.GetByteLength"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.CombinedHash.GetDigestSize">
+            <seealso cref="M:Org.BouncyCastle.Crypto.IDigest.GetDigestSize"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.CombinedHash.Update(System.Byte)">
+            <seealso cref="M:Org.BouncyCastle.Crypto.IDigest.Update(System.Byte)"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.CombinedHash.BlockUpdate(System.Byte[],System.Int32,System.Int32)">
+            <seealso cref="M:Org.BouncyCastle.Crypto.IDigest.BlockUpdate(System.Byte[],System.Int32,System.Int32)"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.CombinedHash.DoFinal(System.Byte[],System.Int32)">
+            <seealso cref="M:Org.BouncyCastle.Crypto.IDigest.DoFinal(System.Byte[],System.Int32)"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.CombinedHash.Reset">
+            <seealso cref="M:Org.BouncyCastle.Crypto.IDigest.Reset"/>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.CombinedHash.AlgorithmName">
+            <seealso cref="P:Org.BouncyCastle.Crypto.IDigest.AlgorithmName"/>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.CompressionMethod">
+            <summary>
+            RFC 2246 6.1
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ContentType">
+            <summary>
+            RFC 2246 6.2.1
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsAgreementCredentials.GenerateAgreement(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsCipherFactory.CreateCipher(Org.BouncyCastle.Crypto.Tls.TlsClientContext,Org.BouncyCastle.Crypto.Tls.EncryptionAlgorithm,Org.BouncyCastle.Crypto.Tls.DigestAlgorithm)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.DefaultTlsCipherFactory.CreateAesCipher(Org.BouncyCastle.Crypto.Tls.TlsClientContext,System.Int32,Org.BouncyCastle.Crypto.Tls.DigestAlgorithm)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.DefaultTlsCipherFactory.CreateDesEdeCipher(Org.BouncyCastle.Crypto.Tls.TlsClientContext,System.Int32,Org.BouncyCastle.Crypto.Tls.DigestAlgorithm)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.DefaultTlsCipherFactory.CreateDigest(Org.BouncyCastle.Crypto.Tls.DigestAlgorithm)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.Init(Org.BouncyCastle.Crypto.Tls.TlsClientContext)">
+            <summary>
+            Called at the start of a new TLS session, before any other methods.
+            </summary>
+            <param name="context">
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler"/>
+            </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetCipherSuites">
+            <summary>
+            Get the list of cipher suites that this client supports.
+            </summary>
+            <returns>
+            An array of <see cref="T:Org.BouncyCastle.Crypto.Tls.CipherSuite"/>, each specifying a supported cipher suite.
+            </returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetCompressionMethods">
+            <summary>
+            Get the list of compression methods that this client supports.
+            </summary>
+            <returns>
+            An array of <see cref="T:Org.BouncyCastle.Crypto.Tls.CompressionMethod"/>, each specifying a supported compression method.
+            </returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetClientExtensions">
+            <summary>
+            Get the (optional) table of client extensions to be included in (extended) client hello.
+            </summary>
+            <returns>
+            A <see cref="T:System.Collections.IDictionary"/> (<see cref="T:Org.BouncyCastle.Crypto.Tls.ExtensionType"/> -&gt; byte[]). May be null.
+            </returns>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.NotifySessionID(System.Byte[])">
+            <summary>
+            Reports the session ID once it has been determined.
+            </summary>
+            <param name="sessionID">
+            A <see cref="T:System.Byte"/>
+            </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.NotifySelectedCipherSuite(Org.BouncyCastle.Crypto.Tls.CipherSuite)">
+            <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="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetCipherSuites"/>
+            </remarks>
+            <param name="selectedCipherSuite">
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.CipherSuite"/>
+            </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.NotifySelectedCompressionMethod(Org.BouncyCastle.Crypto.Tls.CompressionMethod)">
+            <summary>
+            Report the compression method that was selected by the server.
+            </summary>
+            <remarks>
+            The protocol handler validates this value against the offered compression methods
+            <seealso cref="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetCompressionMethods"/>
+            </remarks>
+            <param name="selectedCompressionMethod">
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.CompressionMethod"/>
+            </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.NotifySecureRenegotiation(System.Boolean)">
+            <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="T:System.Boolean"/>, true if the server supports secure renegotiation
+            </param>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.ProcessServerExtensions(System.Collections.IDictionary)">
+            <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="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetClientExtensions"/>.
+            </remarks>
+            <param name="serverExtensions">
+            A <see cref="T:System.Collections.IDictionary"/>  (<see cref="T:Org.BouncyCastle.Crypto.Tls.ExtensionType"/> -&gt; byte[])
+            </param>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetKeyExchange">
+            <summary>
+            Return an implementation of <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange"/> to negotiate the key exchange
+            part of the protocol.
+            </summary>
+            <returns>
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange"/>
+            </returns>
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetAuthentication">
+            <summary>
+            Return an implementation of <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsAuthentication"/> to handle authentication
+            part of the protocol.
+            </summary>
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetCompression">
+            <summary>
+            Return an implementation of <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsCompression"/> to handle record compression.
+            </summary>
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsClient.GetCipher">
+            <summary>
+            Return an implementation of <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsCipher"/> to use for encryption/decryption.
+            </summary>
+            <returns>
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsCipher"/>
+            </returns>
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsSignerCredentials.GenerateCertificateSignature(System.Byte[])">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ECCurveType">
+            <summary>
+            RFC 4492 5.4
+            </summary>
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ECCurveType.explicit_prime">
+            Indicates the elliptic curve domain parameters are conveyed verbosely, and the
+            underlying finite field is a prime field.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ECCurveType.explicit_char2">
+            Indicates the elliptic curve domain parameters are conveyed verbosely, and the
+            underlying finite field is a characteristic-2 field.
+        </member>
+        <member name="F:Org.BouncyCastle.Crypto.Tls.ECCurveType.named_curve">
+            Indicates that a named curve is used. This option SHOULD be used when applicable.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ECPointFormat">
+            <summary>
+            RFC 4492 5.1.2
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.ExtensionType">
+            <summary>
+            RFC 4366 2.3
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.HandshakeType">
+            <summary>
+            RFC 2246 7.4
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.LegacyTlsAuthentication">
+            <summary>
+            A temporary class to wrap old CertificateVerifyer stuff for new TlsAuthentication.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsAuthentication.NotifyServerCertificate(Org.BouncyCastle.Crypto.Tls.Certificate)">
+            <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="T:Org.BouncyCastle.Crypto.Tls.Certificate"/> received</param>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsAuthentication.GetClientCredentials(Org.BouncyCastle.Crypto.Tls.CertificateRequest)">
+            <summary>
+            Return client credentials in response to server's certificate request
+            </summary>
+            <param name="certificateRequest">
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.CertificateRequest"/> containing server certificate request details
+            </param>
+            <returns>
+            A <see cref="T:Org.BouncyCastle.Crypto.Tls.TlsCredentials"/> to be used for client authentication
+            (or <c>null</c> for no client authentication)
+            </returns>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.LegacyTlsClient">
+            <summary>
+            A temporary class to use LegacyTlsAuthentication 
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.NamedCurve">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.RecordStream">
+            <remarks>An implementation of the TLS 1.0 record layer.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.Ssl3Mac">
+            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))
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.Ssl3Mac.#ctor(Org.BouncyCastle.Crypto.IDigest)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.Ssl3Mac.Reset">
+            Reset the mac generator.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsBlockCipher">
+            <summary>
+            A generic TLS 1.0 block cipher. This can be used for AES or 3DES for example.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsCipher.EncodePlaintext(Org.BouncyCastle.Crypto.Tls.ContentType,System.Byte[],System.Int32,System.Int32)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsCipher.DecodeCiphertext(Org.BouncyCastle.Crypto.Tls.ContentType,System.Byte[],System.Int32,System.Int32)">
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsDHKeyExchange">
+            <summary>
+            TLS 1.0 DH key exchange.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange">
+            <summary>
+            A generic interface for key exchange implementations in TLS 1.0.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.SkipServerCertificate">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.ProcessServerCertificate(Org.BouncyCastle.Crypto.Tls.Certificate)">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.SkipServerKeyExchange">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.ProcessServerKeyExchange(System.IO.Stream)">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.ValidateCertificateRequest(Org.BouncyCastle.Crypto.Tls.CertificateRequest)">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.SkipClientCredentials">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.ProcessClientCredentials(Org.BouncyCastle.Crypto.Tls.TlsCredentials)">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.GenerateClientKeyExchange(System.IO.Stream)">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsKeyExchange.GeneratePremasterSecret">
+            <exception cref="T:System.IO.IOException"/>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsECDheKeyExchange">
+            ECDHE key exchange (see RFC 4492)
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsECDHKeyExchange">
+            ECDH key exchange (see RFC 4492)
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsMac">
+            <remarks>
+            A generic TLS MAC implementation, which can be used with any kind of
+            IDigest to act as an HMAC.
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsMac.#ctor(Org.BouncyCastle.Crypto.IDigest,System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsMac.GetMacSecret">
+            @return the MAC write secret
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsMac.IncSequenceNumber">
+            Increment the current write sequence number
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsMac.CalculateMac(Org.BouncyCastle.Crypto.Tls.ContentType,System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.TlsMac.SequenceNumber">
+            @return the current write sequence number
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.TlsMac.Size">
+            @return The Keysize of the mac.
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsNullCipher">
+            <summary>
+            A NULL cipher suite, for use during handshake.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler">
+            <remarks>An implementation of all high level protocols in TLS 1.0.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.#ctor(System.IO.Stream,System.IO.Stream)">
+            <remarks>Both streams can be the same object</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.#ctor(System.IO.Stream,System.IO.Stream,Org.BouncyCastle.Security.SecureRandom)">
+            <remarks>Both streams can be the same object</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.ProcessChangeCipherSpec">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.Connect(Org.BouncyCastle.Crypto.Tls.ICertificateVerifyer)">
+            <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="T:System.IO.IOException">If handshake was not successful</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.ReadApplicationData(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.WriteData(System.Byte[],System.Int32,System.Int32)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.FailWithError(Org.BouncyCastle.Crypto.Tls.AlertLevel,Org.BouncyCastle.Crypto.Tls.AlertDescription)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.Close">
+            <summary>Closes this connection</summary>
+            <exception cref="T:System.IO.IOException">If something goes wrong during closing.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.AssertEmpty(System.IO.MemoryStream)">
+             Make sure the Stream is now empty. Fail otherwise.
+            
+             @param is The Stream to check.
+             @throws IOException If is is not empty.
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.OutputStream">
+            <summary>A Stream which can be used to send data.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.InputStream">
+            <summary>A Stream which can be used to read data.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Crypto.Tls.TlsProtocolHandler.Stream">
+            <summary>The secure bidirectional stream for this connection</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsRsaKeyExchange">
+            <summary>
+            TLS 1.0 RSA key exchange.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsSrpKeyExchange">
+            <summary>
+            TLS 1.1 SRP key exchange.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Crypto.Tls.TlsUtilities">
+            <remarks>Some helper fuctions for MicroTLS.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.AddMagnitudes(System.Int32[],System.Int32[])">
+            return a = a + b - b preserved.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.CompareTo(System.Int32,System.Int32[],System.Int32,System.Int32[])">
+            unsigned comparison on two arrays - note the arrays may
+            start with leading zeros.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.Divide(System.Int32[],System.Int32[])">
+            return z = x / y - done in place (z value preserved, x contains the
+            remainder)
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.IsProbablePrime(System.Int32)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.ExtEuclid(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger@)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.Square(System.Int32[],System.Int32[])">
+            return w with w = x * x - w is assumed to have enough space.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.Multiply(System.Int32[],System.Int32[],System.Int32[])">
+            return x with x = y * z - x is assumed to have enough space.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.GetMQuote">
+            Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size)
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.MultiplyMonty(System.Int32[],System.Int32[],System.Int32[],System.Int32[],System.Int64)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.Remainder(System.Int32[],System.Int32[])">
+            return x = x % y - done in place (y value preserved)
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.ShiftLeft(System.Int32[],System.Int32)">
+            do a left shift - this returns a new array.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.ShiftRightInPlace(System.Int32,System.Int32[],System.Int32)">
+            do a right shift - this does it in place.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.ShiftRightOneInPlace(System.Int32,System.Int32[])">
+            do a right shift by one - this does it in place.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.BigInteger.Subtract(System.Int32,System.Int32[],System.Int32,System.Int32[])">
+            returns x = x - y - we assume x is >= y
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal.GetInstance(Org.BouncyCastle.Math.BigInteger,System.Int32)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal.#ctor(Org.BouncyCastle.Math.BigInteger,System.Int32)">
+            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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Abc.Tnaf">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.Tnaf.Width">
+            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
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.Tnaf.Pow2Width">
+            2<sup>4</sup>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.Tnaf.Alpha0">
+            The <code>&#945;<sub>u</sub></code>'s for <code>a=0</code> as an array
+            of <code>ZTauElement</code>s.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.Tnaf.Alpha0Tnaf">
+            The <code>&#945;<sub>u</sub></code>'s for <code>a=0</code> as an array
+            of TNAFs.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.Tnaf.Alpha1">
+            The <code>&#945;<sub>u</sub></code>'s for <code>a=1</code> as an array
+            of <code>ZTauElement</code>s.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.Tnaf.Alpha1Tnaf">
+            The <code>&#945;<sub>u</sub></code>'s for <code>a=1</code> as an array
+            of TNAFs.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.Norm(System.SByte,Org.BouncyCastle.Math.EC.Abc.ZTauElement)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.Norm(System.SByte,Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal,Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.Round(Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal,Org.BouncyCastle.Math.EC.Abc.SimpleBigDecimal,System.SByte)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.ApproximateDivisionByN(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,System.SByte,System.Int32,System.Int32)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.TauAdicNaf(System.SByte,Org.BouncyCastle.Math.EC.Abc.ZTauElement)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.Tau(Org.BouncyCastle.Math.EC.F2mPoint)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.GetMu(Org.BouncyCastle.Math.EC.F2mCurve)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.GetLucas(System.SByte,System.Int32,System.Boolean)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.GetTw(System.SByte,System.Int32)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.GetSi(Org.BouncyCastle.Math.EC.F2mCurve)">
+            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).
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.PartModReduction(Org.BouncyCastle.Math.BigInteger,System.Int32,System.SByte,Org.BouncyCastle.Math.BigInteger[],System.SByte,System.SByte)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.MultiplyRTnaf(Org.BouncyCastle.Math.EC.F2mPoint,Org.BouncyCastle.Math.BigInteger)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.MultiplyTnaf(Org.BouncyCastle.Math.EC.F2mPoint,Org.BouncyCastle.Math.EC.Abc.ZTauElement)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.MultiplyFromTnaf(Org.BouncyCastle.Math.EC.F2mPoint,System.SByte[])">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.TauAdicWNaf(System.SByte,Org.BouncyCastle.Math.EC.Abc.ZTauElement,System.SByte,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.EC.Abc.ZTauElement[])">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.Tnaf.GetPreComp(Org.BouncyCastle.Math.EC.F2mPoint,System.SByte)">
+            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>. 
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Abc.ZTauElement">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.ZTauElement.u">
+            The &quot;real&quot; part of <code>&#955;</code>.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Abc.ZTauElement.v">
+            The &quot;<code>&#964;</code>-adic&quot; part of <code>&#955;</code>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Abc.ZTauElement.#ctor(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.ECCurve">
+            <remarks>Base class for an elliptic curve.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.ECCurveBase.DecodePoint(System.Byte[])">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.FpCurve">
+            Elliptic curve over Fp
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.F2mCurve">
+            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>.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.m">
+            The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.k1">
+            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/>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.k2">
+            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/>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.k3">
+            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/>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.n">
+            The order of the base point of the curve.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.h">
+            The cofactor of the curve.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.infinity">
+            The point at infinity on this curve.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.mu">
+            The parameter <code>&#956;</code> of the elliptic curve if this is
+            a Koblitz curve.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mCurve.si">
+            The auxiliary values <code>s<sub>0</sub></code> and
+            <code>s<sub>1</sub></code> used for partial modular reduction for
+            Koblitz curves.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.#ctor(System.Int32,System.Int32,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.#ctor(System.Int32,System.Int32,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.GetMu">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.GetSi">
+            @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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.solveQuadradicEquation(Org.BouncyCastle.Math.EC.ECFieldElement)">
+             Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+             D.1.6) The other solution is <code>z + 1</code>.
+            
+             @param beta
+                        The value to solve the qradratic equation for.
+             @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+                     <code>null</code> if no solution exists.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mCurve.IsTrinomial">
+             Return true if curve uses a Trinomial basis.
+            
+             @return true if curve Trinomial, false otherwise.
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.F2mCurve.IsKoblitz">
+            Returns true if this is a Koblitz curve (ABC curve).
+            @return true if this is a Koblitz curve (ABC curve), false otherwise
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.FpFieldElement.Sqrt">
+            return a sqrt root - the routine verifies that the calculation
+            returns the right value - if none exists it returns null.
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.FpFieldElement.FieldName">
+             return the field name for this field.
+            
+             @return the string "Fp".
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.F2mFieldElement">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.Gnb">
+            Indicates gaussian normal basis representation (GNB). Number chosen
+            according to X9.62. GNB is not implemented at present.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.Tpb">
+            Indicates trinomial basis representation (Tpb). Number chosen
+            according to X9.62.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.Ppb">
+            Indicates pentanomial basis representation (Ppb). Number chosen
+            according to X9.62.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.representation">
+            Tpb or Ppb.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.m">
+            The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.k1">
+            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/>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.k2">
+            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/>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.k3">
+            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/>
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.x">
+            The <code>IntArray</code> holding the bits.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.F2mFieldElement.t">
+            The number of <code>int</code>s required to hold <code>m</code> bits.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mFieldElement.#ctor(System.Int32,System.Int32,System.Int32,System.Int32,Org.BouncyCastle.Math.BigInteger)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mFieldElement.#ctor(System.Int32,System.Int32,Org.BouncyCastle.Math.BigInteger)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mFieldElement.CheckFieldElements(Org.BouncyCastle.Math.EC.ECFieldElement,Org.BouncyCastle.Math.EC.ECFieldElement)">
+            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).
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.F2mFieldElement.Representation">
+            @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).
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.F2mFieldElement.M">
+            @return the degree <code>m</code> of the reduction polynomial
+            <code>f(z)</code>.
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.F2mFieldElement.K1">
+            @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/>
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.F2mFieldElement.K2">
+            @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/>
+        </member>
+        <member name="P:Org.BouncyCastle.Math.EC.F2mFieldElement.K3">
+            @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/>
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.ECPoint">
+            base class for points on elliptic curves.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.ECPoint.SetPreCompInfo(Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.ECPoint.AssertECMultiplier">
+            Sets the appropriate <code>ECMultiplier</code>, unless already set. 
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.ECPointBase.GetEncoded">
+            return the field element encoded with point compression. (S 4.3.6)
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.ECPointBase.Multiply(Org.BouncyCastle.Math.BigInteger)">
+            Multiplies this <code>ECPoint</code> by the given number.
+            @param k The multiplicator.
+            @return <code>k * this</code>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.FpPoint">
+            Elliptic curve points over Fp
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.FpPoint.#ctor(Org.BouncyCastle.Math.EC.ECCurve,Org.BouncyCastle.Math.EC.ECFieldElement,Org.BouncyCastle.Math.EC.ECFieldElement)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.FpPoint.#ctor(Org.BouncyCastle.Math.EC.ECCurve,Org.BouncyCastle.Math.EC.ECFieldElement,Org.BouncyCastle.Math.EC.ECFieldElement,System.Boolean)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.FpPoint.AssertECMultiplier">
+            Sets the default <code>ECMultiplier</code>, unless already set. 
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.F2mPoint">
+            Elliptic curve points over F2m
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.#ctor(Org.BouncyCastle.Math.EC.ECCurve,Org.BouncyCastle.Math.EC.ECFieldElement,Org.BouncyCastle.Math.EC.ECFieldElement)">
+            @param curve base curve
+            @param x x point
+            @param y y point
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.#ctor(Org.BouncyCastle.Math.EC.ECCurve,Org.BouncyCastle.Math.EC.ECFieldElement,Org.BouncyCastle.Math.EC.ECFieldElement,System.Boolean)">
+            @param curve base curve
+            @param x x point
+            @param y y point
+            @param withCompression true if encode with point compression.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.#ctor(Org.BouncyCastle.Math.EC.ECCurve)">
+            Constructor for point at infinity
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.CheckPoints(Org.BouncyCastle.Math.EC.ECPoint,Org.BouncyCastle.Math.EC.ECPoint)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.AddSimple(Org.BouncyCastle.Math.EC.F2mPoint)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.SubtractSimple(Org.BouncyCastle.Math.EC.F2mPoint)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.F2mPoint.AssertECMultiplier">
+            Sets the appropriate <code>ECMultiplier</code>, unless already set. 
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.ECMultiplier">
+            Interface for classes encapsulating a point multiplication algorithm
+            for <code>ECPoint</code>s.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.ECMultiplier.Multiply(Org.BouncyCastle.Math.EC.ECPoint,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo)">
+            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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.FpNafMultiplier">
+            Class implementing the NAF (Non-Adjacent Form) multiplication algorithm.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.FpNafMultiplier.Multiply(Org.BouncyCastle.Math.EC.ECPoint,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo)">
+            D.3.2 pg 101
+            @see org.bouncycastle.math.ec.multiplier.ECMultiplier#multiply(org.bouncycastle.math.ec.ECPoint, java.math.BigInteger)
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo">
+            Interface for classes storing precomputation data for multiplication
+            algorithms. Used as a Memento (see GOF patterns) for
+            <code>WNafMultiplier</code>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.ReferenceMultiplier.Multiply(Org.BouncyCastle.Math.EC.ECPoint,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo)">
+            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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.WNafMultiplier">
+            Class implementing the WNAF (Window Non-Adjacent Form) multiplication
+            algorithm.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WNafMultiplier.WindowNaf(System.SByte,Org.BouncyCastle.Math.BigInteger)">
+            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 = &#8722;<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>sbyte[]</code>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WNafMultiplier.Multiply(Org.BouncyCastle.Math.EC.ECPoint,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo)">
+            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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.WNafPreCompInfo">
+            Class holding precomputation data for the WNAF (Window Non-Adjacent Form)
+            algorithm.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Multiplier.WNafPreCompInfo.preComp">
+            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>.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Multiplier.WNafPreCompInfo.twiceP">
+            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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.WTauNafMultiplier">
+            Class implementing the WTNAF (Window
+            <code>&#964;</code>-adic Non-Adjacent Form) algorithm.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WTauNafMultiplier.Multiply(Org.BouncyCastle.Math.EC.ECPoint,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WTauNafMultiplier.MultiplyWTnaf(Org.BouncyCastle.Math.EC.F2mPoint,Org.BouncyCastle.Math.EC.Abc.ZTauElement,Org.BouncyCastle.Math.EC.Multiplier.PreCompInfo,System.SByte,System.SByte)">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WTauNafMultiplier.MultiplyFromWTnaf(Org.BouncyCastle.Math.EC.F2mPoint,System.SByte[],Org.BouncyCastle.Math.EC.Multiplier.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>
+        </member>
+        <member name="T:Org.BouncyCastle.Math.EC.Multiplier.WTauNafPreCompInfo">
+            Class holding precomputation data for the WTNAF (Window
+            <code>&#964;</code>-adic Non-Adjacent Form) algorithm.
+        </member>
+        <member name="F:Org.BouncyCastle.Math.EC.Multiplier.WTauNafPreCompInfo.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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WTauNafPreCompInfo.#ctor(Org.BouncyCastle.Math.EC.F2mPoint[])">
+            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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Math.EC.Multiplier.WTauNafPreCompInfo.GetPreComp">
+            @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>.
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.BasicOcspResp">
+            <remarks>
+            <code>
+            BasicOcspResponse ::= SEQUENCE {
+            	tbsResponseData		ResponseData,
+            	signatureAlgorithm	AlgorithmIdentifier,
+            	signature			BIT STRING,
+            	certs				[0] EXPLICIT SEQUENCE OF Certificate OPTIONAL
+            }
+            </code>
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.IX509Extension.GetCriticalExtensionOids">
+            <summary>
+            Get all critical extension values, by oid
+            </summary>
+            <returns>IDictionary with string (OID) keys and Asn1OctetString values</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.IX509Extension.GetNonCriticalExtensionOids">
+            <summary>
+            Get all non-critical extension values, by oid
+            </summary>
+            <returns>IDictionary with string (OID) keys and Asn1OctetString values</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509ExtensionBase.GetNonCriticalExtensionOids">
+            <summary>
+            Get non critical extensions.
+            </summary>
+            <returns>A set of non critical extension oids.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509ExtensionBase.GetCriticalExtensionOids">
+            <summary>
+            Get any critical extensions.
+            </summary>
+            <returns>A sorted list of critical entension.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509ExtensionBase.GetExtensionValue(System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspResp.GetTbsResponseData">
+            <returns>The DER encoding of the tbsResponseData field.</returns>
+            <exception cref="T:Org.BouncyCastle.Ocsp.OcspException">In the event of an encoding error.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspResp.GetCertificates(System.String)">
+            <returns>The certificates, if any, associated with the response.</returns>
+            <exception cref="T:Org.BouncyCastle.Ocsp.OcspException">In the event of an encoding error.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspResp.Verify(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <summary>
+            Verify the signature against the tbsResponseData object we contain.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspResp.GetEncoded">
+            <returns>The ASN.1 encoded representation of this object.</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator">
+            Generator for basic OCSP response objects.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.#ctor(Org.BouncyCastle.Ocsp.RespID)">
+            basic constructor
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            construct with the responderID to be the SHA-1 keyHash of the passed in public key.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.AddResponse(Org.BouncyCastle.Ocsp.CertificateID,Org.BouncyCastle.Ocsp.CertificateStatus)">
+             Add a response for a particular Certificate ID.
+            
+             @param certID certificate ID details
+             @param certStatus status of the certificate - null if okay
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.AddResponse(Org.BouncyCastle.Ocsp.CertificateID,Org.BouncyCastle.Ocsp.CertificateStatus,Org.BouncyCastle.Asn1.X509.X509Extensions)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.AddResponse(Org.BouncyCastle.Ocsp.CertificateID,Org.BouncyCastle.Ocsp.CertificateStatus,System.DateTime,Org.BouncyCastle.Asn1.X509.X509Extensions)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.AddResponse(Org.BouncyCastle.Ocsp.CertificateID,Org.BouncyCastle.Ocsp.CertificateStatus,System.DateTime,System.DateTime,Org.BouncyCastle.Asn1.X509.X509Extensions)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.SetResponseExtensions(Org.BouncyCastle.Asn1.X509.X509Extensions)">
+             Set the extensions for the response.
+            
+             @param responseExtensions the extension object to carry.
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.BasicOcspRespGenerator.SignatureAlgNames">
+             Return an IEnumerable of the signature names supported by the generator.
+            
+             @return an IEnumerable containing recognised names.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.CertificateID.#ctor(System.String,Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Math.BigInteger)">
+            create from an issuer certificate and the serial number of the
+            certificate it signed.
+            @exception OcspException if any problems occur creating the id fields.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.CertificateID.DeriveCertificateID(Org.BouncyCastle.Ocsp.CertificateID,Org.BouncyCastle.Math.BigInteger)">
+             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
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.CertificateID.SerialNumber">
+            return the serial number for the certificate associated
+            with this request.
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.OcspReq">
+             <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReq.GetTbsRequest">
+            Return the DER encoding of the tbsRequest field.
+            @return DER encoding of tbsRequest
+            @throws OcspException in the event of an encoding error.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReq.GetCertificates(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReq.Verify(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            Verify the signature against the TBSRequest object we contain.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReq.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.OcspReq.SignatureAlgOid">
+            return the object identifier representing the signature algorithm
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.OcspReq.IsSigned">
+             Return whether or not this request is signed.
+            
+             @return true if signed false otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReqGenerator.AddRequest(Org.BouncyCastle.Ocsp.CertificateID)">
+             Add a request for the given CertificateID.
+            
+             @param certId certificate ID of interest
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReqGenerator.AddRequest(Org.BouncyCastle.Ocsp.CertificateID,Org.BouncyCastle.Asn1.X509.X509Extensions)">
+             Add a request with extensions
+            
+             @param certId certificate ID of interest
+             @param singleRequestExtensions the extensions to attach to the request
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReqGenerator.SetRequestorName(Org.BouncyCastle.Asn1.X509.X509Name)">
+             Set the requestor name to the passed in X509Principal
+            
+             @param requestorName a X509Principal representing the requestor name.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspReqGenerator.Generate">
+             Generate an unsigned request
+            
+             @return the OcspReq
+             @throws OcspException
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.OcspReqGenerator.SignatureAlgNames">
+             Return an IEnumerable of the signature names supported by the generator.
+            
+             @return an IEnumerable containing recognised names.
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.OcspResp.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.OCSPRespGenerator">
+            base generator for an OCSP response - at the moment this only supports the
+            generation of responses containing BasicOCSP responses.
+        </member>
+        <member name="F:Org.BouncyCastle.Ocsp.OcspRespStatus.Successful">
+            note 4 is not used.
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.RespID">
+            Carrier for a ResponderID.
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.RevokedStatus">
+            wrapper for the RevokedInfo object
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.RevokedStatus.RevocationReason">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Ocsp.SingleResp.GetCertStatus">
+             Return the status object for the response - null indicates good.
+            
+             @return the status object for the response, null if it is good.
+        </member>
+        <member name="P:Org.BouncyCastle.Ocsp.SingleResp.NextUpdate">
+             return the NextUpdate value - note: this is an optional field so may
+             be returned as null.
+            
+             @return nextUpdate, or null if not present.
+        </member>
+        <member name="T:Org.BouncyCastle.Ocsp.UnknownStatus">
+            wrapper for the UnknownInfo object
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedData">
+            <remarks>Compressed data objects</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedData.GetInputStream">
+            <summary>Get the raw input stream contained in the object.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedData.GetDataStream">
+            <summary>Return an uncompressed input stream which allows reading of the compressed data.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedData.Algorithm">
+            <summary>The algorithm used for compression</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedDataGenerator">
+            <remarks>Class for producing compressed data packets.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedDataGenerator.Open(System.IO.Stream)">
+            <summary>
+            <p>
+            Return an output stream which will save the data being written to
+            the compressed object.
+            </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>
+            <param name="outStr">Stream to be used for output.</param>
+            <returns>A Stream for output of the compressed data.</returns>
+            <exception cref="T:System.ArgumentNullException"></exception>
+            <exception cref="T:System.InvalidOperationException"></exception>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedDataGenerator.Open(System.IO.Stream,System.Byte[])">
+            <summary>
+            <p>
+            Return an output stream which will compress 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>
+            <p>
+            <b>Note</b>: using this may break compatibility with RFC 1991 compliant tools.
+            Only recent OpenPGP implementations are capable of accepting these streams.
+            </p>
+            </summary>
+            <param name="outStr">Stream to be used for output.</param>
+            <param name="buffer">The buffer to use.</param>
+            <returns>A Stream for output of the compressed data.</returns>
+            <exception cref="T:System.ArgumentNullException"></exception>
+            <exception cref="T:System.InvalidOperationException"></exception>
+            <exception cref="T:System.IO.IOException"></exception>
+            <exception cref="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpCompressedDataGenerator.Close">
+            <summary>Close the compressed object.</summary>summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpDataValidationException">
+            <remarks>
+            Thrown if the IV at the start of a data stream indicates the wrong key is being used.
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException">
+            <remarks>Generic exception class for PGP encoding/decoding problems.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedData.GetInputStream">
+            <summary>Return the raw input stream for the data stream.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedData.IsIntegrityProtected">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedData.Verify">
+            <summary>Note: This can only be called after the message has been read.</summary>
+            <returns>True, if the message verifies, false otherwise</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator">
+            <remarks>Generator for encrypted objects.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.#ctor(Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Existing SecureRandom constructor.</summary>
+            <param name="encAlgorithm">The symmetric algorithm to use.</param>
+            <param name="rand">Source of randomness.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.#ctor(Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,System.Boolean,Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Creates a cipher stream which will have an integrity packet associated with it.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.#ctor(Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,Org.BouncyCastle.Security.SecureRandom,System.Boolean)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.AddMethod(System.Char[])">
+            <summary>
+            Add a PBE encryption method to the encrypted object using the default algorithm (S2K_SHA1).
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.AddMethod(System.Char[],Org.BouncyCastle.Bcpg.HashAlgorithmTag)">
+            <summary>Add a PBE encryption method to the encrypted object.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.AddMethod(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Add a public key encrypted session key to the encrypted object.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.Open(System.IO.Stream,System.Int64,System.Byte[])">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.Open(System.IO.Stream,System.Int64)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.Open(System.IO.Stream,System.Byte[])">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataGenerator.Close">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpEncryptedDataList">
+            <remarks>A holder for a list of PGP encryption method packets.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyFlags">
+            <remarks>Key flag values for the KeyFlags subpacket.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair.#ctor(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair.KeyId">
+            <summary>The keyId associated with this key pair.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator">
+            <remarks>
+            Generator for a PGP master and subkey ring.
+            This class will generate both the secret and public key rings
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator.#ctor(System.Int32,Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair,System.String,Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,System.Char[],Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator.#ctor(System.Int32,Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair,System.String,Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,System.Char[],System.Boolean,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator.AddSubKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair)">
+            <summary>Add a subkey to the key ring to be generated with default certification.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator.AddSubKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyPair,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector)">
+            <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="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator.GenerateSecretKeyRing">
+            <summary>Return the secret key ring.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyRingGenerator.GeneratePublicKeyRing">
+            <summary>Return the public key ring that corresponds to the secret key ring.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpKeyValidationException">
+            <remarks>
+            Thrown if the key checksum is invalid.
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData">
+            <summary>Class for processing literal data objects.</summary>
+        </member>
+        <member name="F:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.Console">
+            <summary>The special name indicating a "for your eyes only" packet.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.GetRawFileName">
+            Return the file name as an unintrepreted byte array.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.GetInputStream">
+            <summary>The raw input stream for the data stream.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.GetDataStream">
+            <summary>The input stream representing the data stream.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.Format">
+            <summary>The format of the data stream - Binary or Text</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.FileName">
+            <summary>The file name that's associated with the data stream.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralData.ModificationTime">
+            <summary>The modification time for the file.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralDataGenerator">
+            <remarks>Class for producing literal data packets.</remarks>
+        </member>
+        <member name="F:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralDataGenerator.Console">
+            <summary>The special name indicating a "for your eyes only" packet.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralDataGenerator.#ctor(System.Boolean)">
+            <summary>
+            Generates literal data objects in the old format.
+            This is important if you need compatibility with PGP 2.6.x.
+            </summary>
+            <param name="oldFormat">If true, uses old format.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralDataGenerator.Open(System.IO.Stream,System.Char,System.String,System.Int64,System.DateTime)">
+            <summary>
+            <p>
+            Open a literal data packet, returning a stream to store the data inside the 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>
+            <param name="outStr">The stream we want the packet in.</param>
+            <param name="format">The format we are using.</param>
+            <param name="name">The name of the 'file'.</param>
+            <param name="length">The length of the data we will write.</param>
+            <param name="modificationTime">The time of last modification we want stored.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralDataGenerator.Open(System.IO.Stream,System.Char,System.String,System.DateTime,System.Byte[])">
+            <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
+            packets with a chunk size determined by 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>
+            <param name="outStr">The stream we want the packet in.</param>
+            <param name="format">The format we are using.</param>
+            <param name="name">The name of the 'file'.</param>
+            <param name="modificationTime">The time of last modification we want stored.</param>
+            <param name="buffer">The buffer to use for collecting data to put into chunks.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpLiteralDataGenerator.Close">
+            <summary>
+            Close the literal data packet - this is equivalent to calling Close()
+            on the stream returned by the Open() method.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpMarker">
+            <remarks>
+            A PGP marker packet - in general these should be ignored other than where
+            the idea is to preserve the original input stream.
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpObjectFactory">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpObjectFactory.NextPgpObject">
+            <summary>Return the next object in the stream, or null if the end is reached.</summary>
+            <exception cref="T:System.IO.IOException">On a parse error</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpObjectFactory.AllPgpObjects">
+            <summary>
+            Return all available objects in a list.
+            </summary>
+            <returns>An <c>IList</c> containing all objects from this factory, in order.</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpOnePassSignature">
+            <remarks>A one pass signature object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpOnePassSignature.InitVerify(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Initialise the signature object for verification.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpOnePassSignature.Verify(Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <summary>Verify the calculated signature against the passed in PgpSignature.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpOnePassSignatureList">
+            <remarks>Holder for a list of PgpOnePassSignature objects.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpPbeEncryptedData">
+            <remarks>A password based encryption object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPbeEncryptedData.GetInputStream">
+            <summary>Return the raw input stream for the data stream.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPbeEncryptedData.GetDataStream(System.Char[])">
+            <summary>Return the decrypted input stream, using the passed in passphrase.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey">
+            <remarks>General class to contain a private key for use with other OpenPGP objects.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Int64)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey.KeyId">
+            <summary>The keyId associated with the contained private key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey.Key">
+            <summary>The contained private key.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey">
+            <remarks>General class to handle a PGP public key object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.#ctor(Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.DateTime)">
+            <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="T:System.ArgumentException">If <c>pubKey</c> is not public.</exception>
+            <exception cref="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException">On key creation problem.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.#ctor(Org.BouncyCastle.Bcpg.PublicKeyPacket,Org.BouncyCastle.Bcpg.TrustPacket,System.Collections.IList)">
+            <summary>Constructor for a sub-key.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.#ctor(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Copy constructor.</summary>
+            <param name="pubKey">The public key to copy.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetTrustData">
+            <summary>Return the trust data associated with the public key, if present.</summary>
+            <returns>A byte array with trust data, null otherwise.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetValidSeconds">
+            <summary>The number of valid seconds from creation time - zero means no expiry.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetFingerprint">
+            <summary>The fingerprint of the key</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetKey">
+            <summary>The public key contained in the object.</summary>
+            <returns>A lightweight public key.</returns>
+            <exception cref="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException">If the key algorithm is not recognised.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetUserIds">
+            <summary>Allows enumeration of any user IDs associated with the key.</summary>
+            <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetUserAttributes">
+            <summary>Allows enumeration of any user attribute vectors associated with the key.</summary>
+            <returns>An <c>IEnumerable</c> of <c>PgpUserAttributeSubpacketVector</c> objects.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetSignaturesForId(System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetSignaturesForUserAttribute(Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetSignaturesOfType(System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.GetSignatures">
+            <summary>Allows enumeration of all signatures/certifications associated with this key.</summary>
+            <returns>An <c>IEnumerable</c> with all signatures/certifications.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.IsRevoked">
+            <summary>Check whether this (sub)key has a revocation signature on it.</summary>
+            <returns>True, if this (sub)key has been revoked.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.AddCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,System.String,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.AddCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.RemoveCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.RemoveCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.RemoveCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,System.String,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.RemoveCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.AddCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.RemoveCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.Version">
+            <summary>The version of this key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.CreationTime">
+            <summary>The creation time of this key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.ValidDays">
+            <summary>The number of valid days from creation time - zero means no expiry.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.KeyId">
+            <summary>The keyId associated with the public key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.IsEncryptionKey">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.IsMasterKey">
+            <summary>True, if this is a master key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.Algorithm">
+            <summary>The algorithm code associated with the public key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey.BitStrength">
+            <summary>The strength of the key in bits.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyEncryptedData">
+            <remarks>A public key encrypted data object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyEncryptedData.GetSymmetricAlgorithm(Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey)">
+            <summary>
+            Return the algorithm code for the symmetric algorithm used to encrypt the data.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyEncryptedData.GetDataStream(Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey)">
+            <summary>Return the decrypted data stream for the packet.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyEncryptedData.KeyId">
+            <summary>The key ID for the key used to encrypt the data.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing.GetPublicKey">
+            <summary>Return the first public key in the ring.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing.GetPublicKey(System.Int64)">
+            <summary>Return the public key referred to by the passed in key ID if it is present.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing.GetPublicKeys">
+            <summary>Allows enumeration of all the public keys.</summary>
+            <returns>An <c>IEnumerable</c> of <c>PgpPublicKey</c> objects.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing.InsertPublicKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing.RemovePublicKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle">
+            <remarks>
+            Often a PGP key ring file is made up of a succession of master/sub-key key rings.
+            If you want to read an entire public key file in one hit this is the class for you.
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.#ctor(System.IO.Stream)">
+            <summary>Build a PgpPublicKeyRingBundle from the passed in input stream.</summary>
+            <param name="inputStream">Input stream containing data.</param>
+            <exception cref="T:System.IO.IOException">If a problem parsing the stream occurs.</exception>
+            <exception cref="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException">If an object is encountered which isn't a PgpPublicKeyRing.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.GetKeyRings">
+            <summary>Allow enumeration of the public key rings making up this collection.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.GetKeyRings(System.String)">
+            <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+            <param name="userId">The user ID to be matched.</param>
+            <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.GetKeyRings(System.String,System.Boolean)">
+            <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+            <param name="userId">The user ID to be matched.</param>
+            <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+            <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.GetKeyRings(System.String,System.Boolean,System.Boolean)">
+            <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+            <param name="userId">The user ID to be matched.</param>
+            <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+            <param name="ignoreCase">If true, case is ignored in user ID comparisons.</param>
+            <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.GetPublicKey(System.Int64)">
+            <summary>Return the PGP public key associated with the given key id.</summary>
+            <param name="keyId">The ID of the public key to return.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.GetPublicKeyRing(System.Int64)">
+            <summary>Return the public key ring which contains the key referred to by keyId</summary>
+            <param name="keyId">key ID to match against</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.Contains(System.Int64)">
+            <summary>
+            Return true if a key matching the passed in key ID is present, false otherwise.
+            </summary>
+            <param name="keyID">key ID to look for.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.AddPublicKeyRing(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing)">
+            <summary>
+            Return a new bundle containing the contents of the passed in bundle and
+            the passed in public key ring.
+            </summary>
+            <param name="bundle">The <c>PgpPublicKeyRingBundle</c> the key ring is to be added to.</param>
+            <param name="publicKeyRing">The key ring to be added.</param>
+            <returns>A new <c>PgpPublicKeyRingBundle</c> merging the current one with the passed in key ring.</returns>
+            <exception cref="T:System.ArgumentException">If the keyId for the passed in key ring is already present.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.RemovePublicKeyRing(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing)">
+            <summary>
+            Return a new bundle containing the contents of the passed in bundle with
+            the passed in public key ring removed.
+            </summary>
+            <param name="bundle">The <c>PgpPublicKeyRingBundle</c> the key ring is to be removed from.</param>
+            <param name="publicKeyRing">The key ring to be removed.</param>
+            <returns>A new <c>PgpPublicKeyRingBundle</c> not containing the passed in key ring.</returns>
+            <exception cref="T:System.ArgumentException">If the keyId for the passed in key ring is not present.</exception>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRingBundle.Count">
+            <summary>Return the number of key rings in this collection.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey">
+            <remarks>General class to handle a PGP secret key object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.ExtractPrivateKey(System.Char[])">
+            <summary>Extract a <c>PgpPrivateKey</c> from this secret key's encrypted contents.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.CopyWithNewPassword(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey,System.Char[],System.Char[],Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.ReplacePublicKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <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="T:System.ArgumentException">If KeyId's do not match.</exception>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.IsSigningKey">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.IsMasterKey">
+            <summary>True, if this is a master key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.KeyEncryptionAlgorithm">
+            <summary>The algorithm the key is encrypted with.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.KeyId">
+            <summary>The key ID of the public key associated with this key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.PublicKey">
+            <summary>The public key associated with this key.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.UserIds">
+            <summary>Allows enumeration of any user IDs associated with the key.</summary>
+            <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey.UserAttributes">
+            <summary>Allows enumeration of any user attribute vectors associated with the key.</summary>
+            <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.GetPublicKey">
+            <summary>Return the public key for the master key.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.GetSecretKey">
+            <summary>Return the master private key.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.GetSecretKeys">
+            <summary>Allows enumeration of the secret keys.</summary>
+            <returns>An <c>IEnumerable</c> of <c>PgpSecretKey</c> objects.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.GetExtraPublicKeys">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.ReplacePublicKeys(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKeyRing)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.CopyWithNewPassword(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing,System.Char[],System.Char[],Org.BouncyCastle.Bcpg.SymmetricKeyAlgorithmTag,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.InsertSecretKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing,Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing.RemoveSecretKey(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing,Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKey)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle">
+            <remarks>
+            Often a PGP key ring file is made up of a succession of master/sub-key key rings.
+            If you want to read an entire secret key file in one hit this is the class for you.
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.#ctor(System.IO.Stream)">
+            <summary>Build a PgpSecretKeyRingBundle from the passed in input stream.</summary>
+            <param name="inputStream">Input stream containing data.</param>
+            <exception cref="T:System.IO.IOException">If a problem parsing the stream occurs.</exception>
+            <exception cref="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpException">If an object is encountered which isn't a PgpSecretKeyRing.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.GetKeyRings">
+            <summary>Allow enumeration of the secret key rings making up this collection.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.GetKeyRings(System.String)">
+            <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+            <param name="userId">The user ID to be matched.</param>
+            <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.GetKeyRings(System.String,System.Boolean)">
+            <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+            <param name="userId">The user ID to be matched.</param>
+            <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+            <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.GetKeyRings(System.String,System.Boolean,System.Boolean)">
+            <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+            <param name="userId">The user ID to be matched.</param>
+            <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+            <param name="ignoreCase">If true, case is ignored in user ID comparisons.</param>
+            <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.GetSecretKey(System.Int64)">
+            <summary>Return the PGP secret key associated with the given key id.</summary>
+            <param name="keyId">The ID of the secret key to return.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.GetSecretKeyRing(System.Int64)">
+            <summary>Return the secret key ring which contains the key referred to by keyId</summary>
+            <param name="keyId">The ID of the secret key</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.Contains(System.Int64)">
+            <summary>
+            Return true if a key matching the passed in key ID is present, false otherwise.
+            </summary>
+            <param name="keyID">key ID to look for.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.AddSecretKeyRing(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle,Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing)">
+            <summary>
+            Return a new bundle containing the contents of the passed in bundle and
+            the passed in secret key ring.
+            </summary>
+            <param name="bundle">The <c>PgpSecretKeyRingBundle</c> the key ring is to be added to.</param>
+            <param name="secretKeyRing">The key ring to be added.</param>
+            <returns>A new <c>PgpSecretKeyRingBundle</c> merging the current one with the passed in key ring.</returns>
+            <exception cref="T:System.ArgumentException">If the keyId for the passed in key ring is already present.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.RemoveSecretKeyRing(Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle,Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRing)">
+            <summary>
+            Return a new bundle containing the contents of the passed in bundle with
+            the passed in secret key ring removed.
+            </summary>
+            <param name="bundle">The <c>PgpSecretKeyRingBundle</c> the key ring is to be removed from.</param>
+            <param name="secretKeyRing">The key ring to be removed.</param>
+            <returns>A new <c>PgpSecretKeyRingBundle</c> not containing the passed in key ring.</returns>
+            <exception cref="T:System.ArgumentException">If the keyId for the passed in key ring is not present.</exception>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSecretKeyRingBundle.Count">
+            <summary>Return the number of rings in this collection.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature">
+            <remarks>A PGP signature object.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.VerifyCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>
+            Verify the signature as certifying the passed in public key as associated
+            with the passed in user attributes.
+            </summary>
+            <param name="userAttributes">User attributes the key was stored under.</param>
+            <param name="key">The key to be verified.</param>
+            <returns>True, if the signature matches, false otherwise.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.VerifyCertification(System.String,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>
+            Verify the signature as certifying the passed in public key as associated
+            with the passed in ID.
+            </summary>
+            <param name="id">ID the key was stored under.</param>
+            <param name="key">The key to be verified.</param>
+            <returns>True, if the signature matches, false otherwise.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.VerifyCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Verify a certification for the passed in key against the passed in master key.</summary>
+            <param name="masterKey">The key we are verifying against.</param>
+            <param name="pubKey">The key we are verifying.</param>
+            <returns>True, if the certification is valid, false otherwise.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.VerifyCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Verify a key certification, such as revocation, for the passed in key.</summary>
+            <param name="pubKey">The key we are checking.</param>
+            <returns>True, if the certification is valid, false otherwise.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.Version">
+            <summary>The OpenPGP version number for this signature.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.KeyAlgorithm">
+            <summary>The key algorithm associated with this signature.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.HashAlgorithm">
+            <summary>The hash algorithm associated with this signature.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.KeyId">
+            <summary>The ID of the key that created the signature.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.CreationTime">
+            <summary>The creation time of this signature.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignature.HasSubpackets">
+            <summary>
+            Return true if the signature has either hashed or unhashed subpackets.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator">
+            <remarks>Generator for PGP signatures.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.#ctor(Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,Org.BouncyCastle.Bcpg.HashAlgorithmTag)">
+            <summary>Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.InitSign(System.Int32,Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey)">
+            <summary>Initialise the generator for signing.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.InitSign(System.Int32,Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey,Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Initialise the generator for signing.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.GenerateOnePassVersion(System.Boolean)">
+            <summary>Return the one pass header associated with the current signature.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.Generate">
+            <summary>Return a signature object containing the current signature state.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.GenerateCertification(System.String,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Generate a certification for the passed in ID and key.</summary>
+            <param name="id">The ID we are certifying against the public key.</param>
+            <param name="pubKey">The key we are certifying against the ID.</param>
+            <returns>The certification.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.GenerateCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Generate a certification for the passed in userAttributes.</summary>
+            <param name="userAttributes">The ID we are certifying against the public key.</param>
+            <param name="pubKey">The key we are certifying against the ID.</param>
+            <returns>The certification.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.GenerateCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey,Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Generate a certification for the passed in key against the passed in master key.</summary>
+            <param name="masterKey">The key we are certifying against.</param>
+            <param name="pubKey">The key we are certifying.</param>
+            <returns>The certification.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureGenerator.GenerateCertification(Org.BouncyCastle.Bcpg.OpenPgp.PgpPublicKey)">
+            <summary>Generate a certification, such as a revocation, for the passed in key.</summary>
+            <param name="pubKey">The key we are certifying.</param>
+            <returns>The certification.</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureList">
+            <remarks>A list of PGP signatures - normally in the signature block after literal data.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator">
+            <remarks>Generator for signature subpackets.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetTrust(System.Boolean,System.Int32,System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetKeyExpirationTime(System.Boolean,System.Int64)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetSignatureExpirationTime(System.Boolean,System.Int64)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetSignatureCreationTime(System.Boolean,System.DateTime)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetRevocationReason(System.Boolean,Org.BouncyCastle.Bcpg.RevocationReasonTag,System.String)">
+            <summary>
+            Sets revocation reason sub packet
+            </summary>	    
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetRevocationKey(System.Boolean,Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,System.Byte[])">
+            <summary>
+            Sets revocation key sub packet
+            </summary>	
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketGenerator.SetIssuerKeyID(System.Boolean,System.Int64)">
+            <summary>
+            Sets issuer key sub packet
+            </summary>	
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector">
+            <remarks>Container for a list of signature subpackets.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector.HasSubpacket(Org.BouncyCastle.Bcpg.SignatureSubpacketTag)">
+             Return true if a particular subpacket type exists.
+            
+             @param type type to look for.
+             @return true if present, false otherwise.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector.GetSubpackets(Org.BouncyCastle.Bcpg.SignatureSubpacketTag)">
+            Return all signature subpackets of the passed in type.
+            @param type subpacket type code
+            @return an array of zero or more matching subpackets.
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector.GetSignatureExpirationTime">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector.GetKeyExpirationTime">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Bcpg.OpenPgp.PgpSignatureSubpacketVector.Count">
+            <summary>Return the number of packets this vector contains.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpUserAttributeSubpacketVector">
+            <remarks>Container for a list of user attribute subpackets.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpUtilities">
+            <remarks>Basic utility class.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpUtilities.GetDecoderStream(System.IO.Stream)">
+            <summary>
+            Return either an ArmoredInputStream or a BcpgInputStream based on whether
+            the initial characters of the stream are binary PGP encodings or not.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Bcpg.OpenPgp.PgpV3SignatureGenerator">
+            <remarks>Generator for old style PGP V3 Signatures.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpV3SignatureGenerator.#ctor(Org.BouncyCastle.Bcpg.PublicKeyAlgorithmTag,Org.BouncyCastle.Bcpg.HashAlgorithmTag)">
+            <summary>Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpV3SignatureGenerator.InitSign(System.Int32,Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey)">
+            <summary>Initialise the generator for signing.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpV3SignatureGenerator.InitSign(System.Int32,Org.BouncyCastle.Bcpg.OpenPgp.PgpPrivateKey,Org.BouncyCastle.Security.SecureRandom)">
+            <summary>Initialise the generator for signing.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpV3SignatureGenerator.GenerateOnePassVersion(System.Boolean)">
+            <summary>Return the one pass header associated with the current signature.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Bcpg.OpenPgp.PgpV3SignatureGenerator.Generate">
+            <summary>Return a V3 signature object containing the current signature state.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.OpenSsl.MiscPemGenerator">
+            PEM generator for the original set of PEM objects used in Open SSL.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.IO.Pem.PemObjectGenerator.Generate">
+            <returns>
+            A <see cref="T:Org.BouncyCastle.Utilities.IO.Pem.PemObject"/>
+            </returns>
+            <exception cref="T:Org.BouncyCastle.Utilities.IO.Pem.PemGenerationException"></exception>
+        </member>
+        <member name="T:Org.BouncyCastle.OpenSsl.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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.IO.Pem.PemReader.ReadPemObject">
+            <returns>
+            A <see cref="T:Org.BouncyCastle.Utilities.IO.Pem.PemObject"/>
+            </returns>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.#ctor(System.IO.TextReader)">
+             Create a new PemReader
+            
+             @param reader the Reader
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.#ctor(System.IO.TextReader,Org.BouncyCastle.OpenSsl.IPasswordFinder)">
+             Create a new PemReader with a password finder
+            
+             @param reader the Reader
+             @param pFinder the password finder
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.ReadCertificate(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+             Reads in a X509Certificate.
+            
+             @return the X509Certificate
+             @throws IOException if an I/O error occured
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.ReadCrl(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+             Reads in a X509CRL.
+            
+             @return the X509Certificate
+             @throws IOException if an I/O error occured
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.ReadCertificateRequest(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+             Reads in a PKCS10 certification request.
+            
+             @return the certificate request.
+             @throws IOException if an I/O error occured
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.ReadAttributeCertificate(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+             Reads in a X509 Attribute Certificate.
+            
+             @return the X509 Attribute Certificate
+             @throws IOException if an I/O error occured
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.ReadPkcs7(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemReader.ReadPrivateKey(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+            Read a Key Pair
+        </member>
+        <member name="T:Org.BouncyCastle.OpenSsl.PemWriter">
+            <remarks>General purpose writer for OpenSSL PEM objects.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.IO.Pem.PemWriter">
+            A generic PEM writer, based on RFC 1421
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.IO.Pem.PemWriter.#ctor(System.IO.TextWriter)">
+             Base constructor.
+            
+             @param out output stream to use.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.IO.Pem.PemWriter.GetOutputSize(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.PemWriter.#ctor(System.IO.TextWriter)">
+            <param name="writer">The TextWriter object to write the output to.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.Pkcs8Generator.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+             Constructor for an unencrypted private key PEM object.
+            
+             @param key private key to be encoded.
+        </member>
+        <member name="M:Org.BouncyCastle.OpenSsl.Pkcs8Generator.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.String)">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest">
+             <remarks>
+             A class for verifying and creating Pkcs10 Certification requests.
+             </remarks>
+             <code>
+             CertificationRequest ::= Sequence {
+               certificationRequestInfo  CertificationRequestInfo,
+               signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+               signature                 BIT STRING
+             }
+            
+             CertificationRequestInfo ::= Sequence {
+               version             Integer { v1(0) } (v1,...),
+               subject             Name,
+               subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+               attributes          [0] Attributes{{ CRIAttributes }}
+              }
+            
+              Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }}
+            
+              Attr { ATTRIBUTE:IOSet } ::= Sequence {
+                type    ATTRIBUTE.&amp;id({IOSet}),
+                values  Set SIZE(1..MAX) OF ATTRIBUTE.&amp;Type({IOSet}{\@type})
+              }
+             </code>
+             see <a href="http://www.rsasecurity.com/rsalabs/node.asp?id=2132"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest.#ctor(System.String,Org.BouncyCastle.Asn1.X509.X509Name,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Asn1.Asn1Set,Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+             <summary>
+             Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+             </summary>
+            <param name="signatureAlgorithm">Name of Sig Alg.</param>
+             <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param>
+             <param name="publicKey">Public Key to be included in cert reqest.</param>
+             <param name="attributes">ASN1Set of Attributes.</param>
+             <param name="signingKey">Matching Private key for nominated (above) public key to be used to sign the request.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest.GetPublicKey">
+            <summary>
+            Get the public key.
+            </summary>
+            <returns>The public key.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest.Verify">
+            <summary>
+            Verify Pkcs10 Cert Request is valid.
+            </summary>
+            <returns>true = valid.</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequestDelaySigned">
+             <remarks>
+             A class for creating and verifying Pkcs10 Certification requests (this is an extension on <see cref="T:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequest"/>).
+             The requests are made using delay signing. This is useful for situations where
+             the private key is in another environment and not directly accessible (e.g. HSM)
+             So the first step creates the request, then the signing is done outside this
+             object and the signature is then used to complete the request.
+             </remarks>
+             <code>
+             CertificationRequest ::= Sequence {
+               certificationRequestInfo  CertificationRequestInfo,
+               signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+               signature                 BIT STRING
+             }
+            
+             CertificationRequestInfo ::= Sequence {
+               version             Integer { v1(0) } (v1,...),
+               subject             Name,
+               subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+               attributes          [0] Attributes{{ CRIAttributes }}
+              }
+            
+              Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }}
+            
+              Attr { ATTRIBUTE:IOSet } ::= Sequence {
+                type    ATTRIBUTE.&amp;id({IOSet}),
+                values  Set SIZE(1..MAX) OF ATTRIBUTE.&amp;Type({IOSet}{\@type})
+              }
+             </code>
+             see <a href="http://www.rsasecurity.com/rsalabs/node.asp?id=2132"/>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequestDelaySigned.#ctor(System.String,Org.BouncyCastle.Asn1.X509.X509Name,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Asn1.Asn1Set)">
+            <summary>
+            Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+            </summary>
+            <param name="signatureAlgorithm">Name of Sig Alg.</param>
+            <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param>
+            <param name="publicKey">Public Key to be included in cert reqest.</param>
+            <param name="attributes">ASN1Set of Attributes.</param>
+            <remarks>
+            After the object is constructed use the <see cref="M:Org.BouncyCastle.Pkcs.Pkcs10CertificationRequestDelaySigned.GetDataToSign"/> and finally the
+            SignRequest methods to finalize the request.
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs12Store.GetCertificate(System.String)">
+            simply return the cert entry for the private key
+        </member>
+        <member name="T:Org.BouncyCastle.Pkcs.Pkcs12Utilities">
+            Utility class for reencoding PKCS#12 files to definite length.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs12Utilities.ConvertToDefiniteLength(System.Byte[])">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkcs.Pkcs12Utilities.ConvertToDefiniteLength(System.Byte[],System.Char[])">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.CertStatus.RevocationDate">
+            <summary>
+            Returns the revocationDate.
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.CertStatus.Status">
+            <summary>
+            Returns the certStatus.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixAttrCertChecker.GetSupportedExtensions">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixAttrCertChecker.Check(Org.BouncyCastle.X509.IX509AttributeCertificate,Org.BouncyCastle.Pkix.PkixCertPath,Org.BouncyCastle.Pkix.PkixCertPath,System.Collections.ICollection)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixAttrCertChecker.Clone">
+            Returns a clone of this object.
+            
+            @return a copy of this <code>PkixAttrCertChecker</code>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixAttrCertPathBuilder.Build(Org.BouncyCastle.Pkix.PkixBuilderParameters)">
+             Build and validate a CertPath using the given parameter.
+            
+             @param params PKIXBuilderParameters object containing all information to
+                        build the CertPath
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixAttrCertPathValidator">
+            CertPathValidatorSpi implementation for X.509 Attribute Certificates la RFC 3281.
+            
+            @see org.bouncycastle.x509.ExtendedPkixParameters
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixAttrCertPathValidator.Validate(Org.BouncyCastle.Pkix.PkixCertPath,Org.BouncyCastle.Pkix.PkixParameters)">
+            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.
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixBuilderParameters">
+            <summary>
+            Summary description for PkixBuilderParameters.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixParameters">
+            <summary>
+            Summary description for PkixParameters.
+            </summary>
+        </member>
+        <member name="F:Org.BouncyCastle.Pkix.PkixParameters.PkixValidityModel">
+            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.
+        </member>
+        <member name="F:Org.BouncyCastle.Pkix.PkixParameters.ChainValidityModel">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.#ctor(Org.BouncyCastle.Utilities.Collections.ISet)">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetTargetCertConstraints">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetTargetCertConstraints(Org.BouncyCastle.X509.Store.IX509Selector)">
+             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()
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetInitialPolicies">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetInitialPolicies(Org.BouncyCastle.Utilities.Collections.ISet)">
+             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()
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetCertPathCheckers(System.Collections.IList)">
+             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()
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetCertPathCheckers">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.AddCertPathChecker(Org.BouncyCastle.Pkix.PkixCertPathChecker)">
+             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).
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetParams(Org.BouncyCastle.Pkix.PkixParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetStores(System.Collections.IList)">
+             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}.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.AddStore(Org.BouncyCastle.X509.Store.IX509Store)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.AddAdditionalStore(Org.BouncyCastle.X509.Store.IX509Store)">
+             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()
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetAdditionalStores">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetStores">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetAdditionalLocationsEnabled(System.Boolean)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetTargetConstraints">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetTargetConstraints(Org.BouncyCastle.X509.Store.IX509Selector)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetTrustedACIssuers">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetTrustedACIssuers(Org.BouncyCastle.Utilities.Collections.ISet)">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetNecessaryACAttributes">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetNecessaryACAttributes(Org.BouncyCastle.Utilities.Collections.ISet)">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetProhibitedACAttributes">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetProhibitedACAttributes(Org.BouncyCastle.Utilities.Collections.ISet)">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.GetAttrCertCheckers">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixParameters.SetAttrCertCheckers(Org.BouncyCastle.Utilities.Collections.ISet)">
+             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>.
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixParameters.IsUseDeltasEnabled">
+            Whether delta CRLs should be used for checking the revocation status.
+            Defaults to <code>false</code>.
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixParameters.ValidityModel">
+            The validity model.
+            @see #CHAIN_VALIDITY_MODEL
+            @see #PKIX_VALIDITY_MODEL
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixParameters.IsAdditionalLocationsEnabled">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixBuilderParameters.GetInstance(Org.BouncyCastle.Pkix.PkixParameters)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixBuilderParameters.GetExcludedCerts">
+            <summary>
+            Excluded certificates are not used for building a certification path.
+            </summary>
+            <returns>the excluded certificates.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixBuilderParameters.SetExcludedCerts(Org.BouncyCastle.Utilities.Collections.ISet)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixBuilderParameters.SetParams(Org.BouncyCastle.Pkix.PkixParameters)">
+            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)
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixBuilderParameters.Clone">
+             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
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPath">
+             An immutable sequence of certificates (a certification path).<br />
+             <br />
+             This is an abstract class that defines the methods common to all CertPaths.
+             Subclasses can handle different kinds of certificates (X.509, PGP, etc.).<br />
+             <br />
+             All CertPath objects have a type, a list of Certificates, and one or more
+             supported encodings. Because the CertPath class is immutable, a CertPath
+             cannot change in any externally visible way after being constructed. This
+             stipulation applies to all public fields and methods of this class and any
+             added or overridden by subclasses.<br />
+             <br />
+             The type is a string that identifies the type of Certificates in the
+             certification path. For each certificate cert in a certification path
+             certPath, cert.getType().equals(certPath.getType()) must be true.<br />
+             <br />
+             The list of Certificates is an ordered List of zero or more Certificates.
+             This List and all of the Certificates contained in it must be immutable.<br />
+             <br />
+             Each CertPath object must support one or more encodings so that the object
+             can be translated into a byte array for storage or transmission to other
+             parties. Preferably, these encodings should be well-documented standards
+             (such as PKCS#7). One of the encodings supported by a CertPath is considered
+             the default encoding. This encoding is used if no encoding is explicitly
+             requested (for the {@link #getEncoded()} method, for instance).<br />
+             <br />
+             All CertPath objects are also Serializable. CertPath objects are resolved
+             into an alternate {@link CertPathRep} object during serialization. This
+             allows a CertPath object to be serialized into an equivalent representation
+             regardless of its underlying implementation.<br />
+             <br />
+             CertPath objects can be created with a CertificateFactory or they can be
+             returned by other classes, such as a CertPathBuilder.<br />
+             <br />
+             By convention, X.509 CertPaths (consisting of X509Certificates), are ordered
+             starting with the target certificate and ending with a certificate issued by
+             the trust anchor. That is, the issuer of one certificate is the subject of
+             the following one. The certificate representing the
+             {@link TrustAnchor TrustAnchor} should not be included in the certification
+             path. Unvalidated X.509 CertPaths may not follow these conventions. PKIX
+             CertPathValidators will detect any departure from these conventions that
+             cause the certification path to be invalid and throw a
+             CertPathValidatorException.<br />
+             <br />
+             <strong>Concurrent Access</strong><br />
+             <br />
+             All CertPath objects must be thread-safe. That is, multiple threads may
+             concurrently invoke the methods defined in this class on a single CertPath
+             object (or more than one) with no ill effects. This is also true for the List
+             returned by CertPath.getCertificates.<br />
+             <br />
+             Requiring CertPath objects to be immutable and thread-safe allows them to be
+             passed around to various pieces of code without worrying about coordinating
+             access. Providing this thread-safety is generally not difficult, since the
+             CertPath and List objects in question are immutable.
+            
+             @see CertificateFactory
+             @see CertPathBuilder
+            <summary>
+            CertPath implementation for X.509 certificates.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.SortCerts(System.Collections.IList)">
+            @param certs
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.#ctor(System.Collections.ICollection)">
+             Creates a CertPath of the specified type.
+             This constructor is protected because most users should use
+             a CertificateFactory to create CertPaths.
+             @param type the standard name of the type of Certificatesin this path
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.#ctor(System.IO.Stream,System.String)">
+             Creates a CertPath of the specified type.
+             This constructor is protected because most users should use
+             a CertificateFactory to create CertPaths.
+            
+             @param type the standard name of the type of Certificatesin this path
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.Equals(System.Object)">
+             Compares this certification path for equality with the specified object.
+             Two CertPaths are equal if and only if their types are equal and their
+             certificate Lists (and by implication the Certificates in those Lists)
+             are equal. A CertPath is never equal to an object that is not a CertPath.<br />
+             <br />
+             This algorithm is implemented by this method. If it is overridden, the
+             behavior specified here must be maintained.
+            
+             @param other
+                        the object to test for equality with this certification path
+            
+             @return true if the specified object is equal to this certification path,
+                     false otherwise
+            
+             @see Object#hashCode() Object.hashCode()
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.GetEncoded">
+             Returns the encoded form of this certification path, using
+             the default encoding.
+            
+             @return the encoded bytes
+             @exception CertificateEncodingException if an encoding error occurs
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.GetEncoded(System.String)">
+             Returns the encoded form of this certification path, using
+             the specified encoding.
+            
+             @param encoding the name of the encoding to use
+             @return the encoded bytes
+             @exception CertificateEncodingException if an encoding error
+             occurs or the encoding requested is not supported
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPath.ToAsn1Object(Org.BouncyCastle.X509.X509Certificate)">
+             Return a DERObject containing the encoded certificate.
+            
+             @param cert the X509Certificate object to be encoded
+            
+             @return the DERObject
+            
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixCertPath.Encodings">
+             Returns an iteration of the encodings supported by this
+             certification path, with the default encoding
+             first. Attempts to modify the returned Iterator via its
+             remove method result in an UnsupportedOperationException.
+            
+             @return an Iterator over the names of the supported encodings (as Strings)
+            
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixCertPath.Certificates">
+            <summary>
+            Returns the list of certificates in this certification
+            path.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathBuilder">
+             Implements the PKIX CertPathBuilding algorithm for BouncyCastle.
+            
+             @see CertPathBuilderSpi
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathBuilder.Build(Org.BouncyCastle.Pkix.PkixBuilderParameters)">
+             Build and validate a CertPath using the given parameter.
+            
+             @param params PKIXBuilderParameters object containing all information to
+                        build the CertPath
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathBuilderException">
+            <summary>
+            Summary description for PkixCertPathBuilderException.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathBuilderResult">
+            <summary>
+            Summary description for PkixCertPathBuilderResult.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathValidatorResult">
+            <summary>
+            Summary description for PkixCertPathValidatorResult.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathChecker.Init(System.Boolean)">
+                     * 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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathChecker.IsForwardCheckingSupported">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathChecker.GetSupportedExtensions">
+                     * 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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathChecker.Check(Org.BouncyCastle.X509.X509Certificate,System.Collections.ICollection)">
+            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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathChecker.Clone">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathValidator">
+            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>
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathValidatorException">
+             An exception indicating one of a variety of problems encountered when 
+             validating a certification path. <br />
+             <br />
+             A <code>CertPathValidatorException</code> provides support for wrapping
+             exceptions. The {@link #getCause getCause} method returns the throwable, 
+             if any, that caused this exception to be thrown. <br />
+             <br />
+             A <code>CertPathValidatorException</code> may also include the 
+             certification path that was being validated when the exception was thrown 
+             and the index of the certificate in the certification path that caused the 
+             exception to be thrown. Use the {@link #getCertPath getCertPath} and
+             {@link #getIndex getIndex} methods to retrieve this information.<br />
+             <br />
+             <b>Concurrent Access</b><br />
+             <br />
+             Unless otherwise specified, the methods defined in this class are not
+             thread-safe. Multiple threads that need to access a single
+             object concurrently should synchronize amongst themselves and
+             provide the necessary locking. Multiple threads each manipulating
+             separate objects need not synchronize.
+            
+             @see CertPathValidator
+            
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorException.#ctor(System.String)">
+            <summary>
+            Creates a <code>PkixCertPathValidatorException</code> with the given detail
+            message. A detail message is a <code>String</code> that describes this
+            particular exception. 
+            </summary>
+            <param name="message">the detail message</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorException.#ctor(System.String,System.Exception)">
+            <summary>
+            Creates a <code>PkixCertPathValidatorException</code> with the specified
+            detail message and cause.
+            </summary>
+            <param name="message">the detail message</param>
+            <param name="cause">the cause (which is saved for later retrieval by the
+            {@link #getCause getCause()} method). (A <code>null</code>
+            value is permitted, and indicates that the cause is
+            nonexistent or unknown.)</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorException.#ctor(System.String,System.Exception,Org.BouncyCastle.Pkix.PkixCertPath,System.Int32)">
+            <summary>
+            Creates a <code>PkixCertPathValidatorException</code> with the specified
+            detail message, cause, certification path, and index.
+            </summary>
+            <param name="message">the detail message (or <code>null</code> if none)</param>
+            <param name="cause">the cause (or <code>null</code> if none)</param>
+            <param name="certPath">the certification path that was in the process of being
+            validated when the error was encountered</param>
+            <param name="index">the index of the certificate in the certification path that</param>																																																																																   * 
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixCertPathValidatorException.Message">
+            <summary>
+            Returns the detail message for this <code>CertPathValidatorException</code>.
+            </summary>
+            <returns>the detail message, or <code>null</code> if neither the message nor cause were specified</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixCertPathValidatorException.CertPath">
+            Returns the certification path that was being validated when the
+            exception was thrown.
+            
+            @return the <code>CertPath</code> that was being validated when the
+                    exception was thrown (or <code>null</code> if not specified)
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.PkixCertPathValidatorException.Index">
+            Returns the index of the certificate in the certification path that
+            caused the exception to be thrown. Note that the list of certificates in
+            a <code>CertPath</code> is zero based. If no index has been set, -1 is
+            returned.
+            
+            @return the index that has been set, or -1 if none has been set
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities">
+            <summary>
+            Summary description for PkixCertPathValidatorUtilities.
+            </summary>
+        </member>
+        <member name="F:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.KEY_CERT_SIGN">
+            <summary>
+            key usage bits
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.FindTrustAnchor(Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Utilities.Collections.ISet)">
+            <summary>
+            Search the given Set of TrustAnchor's for one that is the
+            issuer of the given X509 certificate.
+            </summary>
+            <param name="cert">the X509 certificate</param>
+            <param name="trustAnchors">a Set of TrustAnchor's</param>
+            <returns>the <code>TrustAnchor</code> object if found or
+            <code>null</code> if not.
+            </returns>
+            @exception
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.GetIssuerPrincipal(System.Object)">
+            <summary>
+            Returns the issuer of an attribute certificate or certificate.
+            </summary>
+            <param name="cert">The attribute certificate or certificate.</param>
+            <returns>The issuer as <code>X500Principal</code>.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.GetNextWorkingKey(System.Collections.IList,System.Int32)">
+             Return the next working key inheriting DSA parameters if necessary.
+             <p>
+             This methods inherits DSA parameters from the indexed certificate or
+             previous certificates in the certificate chain to the returned
+             <code>PublicKey</code>. The list is searched upwards, meaning the end
+             certificate is at position 0 and previous certificates are following.
+             </p>
+             <p>
+             If the indexed certificate does not contain a DSA key this method simply
+             returns the public key. If the DSA key already contains DSA parameters
+             the key is also only returned.
+             </p>
+            
+             @param certs The certification path.
+             @param index The index of the certificate which contains the public key
+                        which should be extended with DSA parameters.
+             @return The public key of the certificate in list position
+                     <code>index</code> extended with DSA parameters if applicable.
+             @throws Exception if DSA parameters cannot be inherited.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.FindCertificates(Org.BouncyCastle.X509.Store.X509CertStoreSelector,System.Collections.IList)">
+            <summary>
+            Return a Collection of all certificates or attribute certificates found
+            in the X509Store's that are matching the certSelect criteriums.
+            </summary>
+            <param name="certSelect">a {@link Selector} object that will be used to select
+            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="T:Org.BouncyCastle.X509.X509Certificate"/> or
+            org.bouncycastle.x509.X509AttributeCertificate objects.
+            May be empty but never <code>null</code>.</returns>
+            <exception cref="T:System.Exception"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.GetCrlIssuersFromDistributionPoint(Org.BouncyCastle.Asn1.X509.DistributionPoint,System.Collections.ICollection,Org.BouncyCastle.X509.Store.X509CrlStoreSelector,Org.BouncyCastle.Pkix.PkixParameters)">
+             Add the CRL issuers from the cRLIssuer field of the distribution point or
+             from the certificate if not given to the issuer criterion of the
+             <code>selector</code>.
+             <p>
+             The <code>issuerPrincipals</code> are a collection with a single
+             <code>X500Principal</code> for <code>X509Certificate</code>s. For
+             {@link X509AttributeCertificate}s the issuer may contain more than one
+             <code>X500Principal</code>.
+             </p>
+            
+             @param dp The distribution point.
+             @param issuerPrincipals The issuers of the certificate or attribute
+                        certificate which contains the distribution point.
+             @param selector The CRL selector.
+             @param pkixParams The PKIX parameters containing the cert stores.
+             @throws Exception if an exception occurs while processing.
+             @throws ClassCastException if <code>issuerPrincipals</code> does not
+             contain only <code>X500Principal</code>s.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.GetCompleteCrls(Org.BouncyCastle.Asn1.X509.DistributionPoint,System.Object,System.DateTime,Org.BouncyCastle.Pkix.PkixParameters)">
+             Fetches complete CRLs according to RFC 3280.
+            
+             @param dp The distribution point for which the complete CRL
+             @param cert The <code>X509Certificate</code> or
+                        {@link org.bouncycastle.x509.X509AttributeCertificate} for
+                        which the CRL should be searched.
+             @param currentDate The date for which the delta CRLs must be valid.
+             @param paramsPKIX The extended PKIX parameters.
+             @return A <code>Set</code> of <code>X509CRL</code>s with complete
+                     CRLs.
+             @throws Exception if an exception occurs while picking the CRLs
+                         or no CRLs are found.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.GetDeltaCrls(System.DateTime,Org.BouncyCastle.Pkix.PkixParameters,Org.BouncyCastle.X509.X509Crl)">
+             Fetches delta CRLs according to RFC 3280 section 5.2.4.
+            
+             @param currentDate The date for which the delta CRLs must be valid.
+             @param paramsPKIX The extended PKIX parameters.
+             @param completeCRL The complete CRL the delta CRL is for.
+             @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
+             @throws Exception if an exception occurs while picking the delta
+                         CRLs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.FindIssuerCerts(Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Pkix.PkixBuilderParameters)">
+             Find the issuer certificates of a given certificate.
+            
+             @param cert
+                        The certificate for which an issuer should be found.
+             @param pkixParams
+             @return A <code>Collection</code> object containing the issuer
+                     <code>X509Certificate</code>s. Never <code>null</code>.
+            
+             @exception Exception
+                            if an error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCertPathValidatorUtilities.GetExtensionValue(Org.BouncyCastle.X509.IX509Extension,Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            <summary>
+            Extract the value of the given extension, if it exists.
+            </summary>
+            <param name="ext">The extension object.</param>
+            <param name="oid">The object identifier to obtain.</param>
+            <returns>Asn1Object</returns>
+            <exception cref="T:System.Exception">if the extension cannot be read.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixCrlUtilities.FindCrls(Org.BouncyCastle.X509.Store.X509CrlStoreSelector,System.Collections.IList)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.IntersectIP(Org.BouncyCastle.Utilities.Collections.ISet,Org.BouncyCastle.Utilities.Collections.ISet)">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.UnionIP(Org.BouncyCastle.Utilities.Collections.ISet,System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.UnionIPRange(System.Byte[],System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.IntersectIPRange(System.Byte[],System.Byte[])">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.IpWithSubnetMask(System.Byte[],System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.ExtractIPsAndSubnetMasks(System.Byte[],System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.MinMaxIPs(System.Byte[],System.Byte[],System.Byte[],System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.CheckPermittedIP(Org.BouncyCastle.Utilities.Collections.ISet,System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.checkExcludedIP(Org.BouncyCastle.Utilities.Collections.ISet,System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.IsIPConstrained(System.Byte[],System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.unionEmail(System.String,System.String,Org.BouncyCastle.Utilities.Collections.ISet)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.intersectEmail(System.String,System.String,Org.BouncyCastle.Utilities.Collections.ISet)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.checkPermitted(Org.BouncyCastle.Asn1.X509.GeneralName)">
+             Checks if the given GeneralName is in the permitted ISet.
+            
+             @param name The GeneralName
+             @throws PkixNameConstraintValidatorException
+                      If the <code>name</code>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.checkExcluded(Org.BouncyCastle.Asn1.X509.GeneralName)">
+             Check if the given GeneralName is contained in the excluded ISet.
+            
+             @param name The GeneralName.
+             @throws PkixNameConstraintValidatorException
+                      If the <code>name</code> is
+                      excluded.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.IntersectPermittedSubtree(Org.BouncyCastle.Asn1.Asn1Sequence)">
+             Updates the permitted ISet of these name constraints with the intersection
+             with the given subtree.
+            
+             @param permitted The permitted subtrees
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.AddExcludedSubtree(Org.BouncyCastle.Asn1.X509.GeneralSubtree)">
+             Adds a subtree to the excluded ISet of these name constraints.
+            
+             @param subtree A subtree with an excluded GeneralName.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.Max(System.Byte[],System.Byte[])">
+             Returns the maximum IP address.
+            
+             @param ip1 The first IP address.
+             @param ip2 The second IP address.
+             @return The maximum IP address.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.Min(System.Byte[],System.Byte[])">
+             Returns the minimum IP address.
+            
+             @param ip1 The first IP address.
+             @param ip2 The second IP address.
+             @return The minimum IP address.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.CompareTo(System.Byte[],System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.Or(System.Byte[],System.Byte[])">
+             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>.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixNameConstraintValidator.StringifyIP(System.Byte[])">
+             Stringifies an IPv4 or v6 address with subnet mask.
+            
+             @param ip The IP with subnet mask.
+             @return The stringified IP address.
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.PkixPolicyNode">
+            <summary>
+            Summary description for PkixPolicyNode.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.PkixPolicyNode.#ctor(System.Collections.IList,System.Int32,Org.BouncyCastle.Utilities.Collections.ISet,Org.BouncyCastle.Pkix.PkixPolicyNode,Org.BouncyCastle.Utilities.Collections.ISet,System.String,System.Boolean)">
+            Constructors
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.ReasonsMask">
+            <summary>
+            This class helps to handle CRL revocation reasons mask. Each CRL handles a
+            certain set of revocation reasons.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.ReasonsMask.#ctor(System.Int32)">
+            <summary>
+            Constructs are reason mask with the reasons.
+            </summary>
+            <param name="reasons">The reasons.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.ReasonsMask.#ctor">
+            <summary>
+            A reason mask with no reason.
+            </summary>
+        </member>
+        <member name="F:Org.BouncyCastle.Pkix.ReasonsMask.AllReasons">
+            <summary>
+            A mask with all revocation reasons.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.ReasonsMask.AddReasons(Org.BouncyCastle.Pkix.ReasonsMask)">
+             Adds all reasons from the reasons mask to this mask.
+            
+             @param mask The reasons mask to add.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.ReasonsMask.Intersect(Org.BouncyCastle.Pkix.ReasonsMask)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.ReasonsMask.HasNewReasons(Org.BouncyCastle.Pkix.ReasonsMask)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.ReasonsMask.IsAllReasons">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.ReasonsMask.Reasons">
+            <summary>
+            Returns the reasons in this mask.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3280CertPathUtilities.ProcessCrlB2(Org.BouncyCastle.Asn1.X509.DistributionPoint,System.Object,Org.BouncyCastle.X509.X509Crl)">
+             If the complete CRL includes an issuing distribution point (IDP) CRL
+             extension check the following:
+             <p>
+             (i) If the distribution point name is present in the IDP CRL extension
+             and the distribution field is present in the DP, then verify that one of
+             the names in the IDP matches one of the names in the DP. If the
+             distribution point name is present in the IDP CRL extension and the
+             distribution field is omitted from the DP, then verify that one of the
+             names in the IDP matches one of the names in the cRLIssuer field of the
+             DP.
+             </p>
+             <p>
+             (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL
+             extension, verify that the certificate does not include the basic
+             constraints extension with the cA boolean asserted.
+             </p>
+             <p>
+             (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL
+             extension, verify that the certificate includes the basic constraints
+             extension with the cA boolean asserted.
+             </p>
+             <p>
+             (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted.
+             </p>
+            
+             @param dp   The distribution point.
+             @param cert The certificate.
+             @param crl  The CRL.
+             @throws AnnotatedException if one of the conditions is not met or an error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3280CertPathUtilities.ProcessCrlB1(Org.BouncyCastle.Asn1.X509.DistributionPoint,System.Object,Org.BouncyCastle.X509.X509Crl)">
+             If the DP includes cRLIssuer, then verify that the issuer field in the
+             complete CRL matches cRLIssuer in the DP and that the complete CRL
+             contains an
+                  g distribution point extension with the indirectCRL
+             boolean asserted. Otherwise, verify that the CRL issuer matches the
+             certificate issuer.
+            
+             @param dp   The distribution point.
+             @param cert The certificate ot attribute certificate.
+             @param crl  The CRL for <code>cert</code>.
+             @throws AnnotatedException if one of the above conditions does not apply or an error
+                                        occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3280CertPathUtilities.ProcessCrlF(Org.BouncyCastle.X509.X509Crl,System.Object,Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Pkix.PkixParameters,System.Collections.IList)">
+             Obtain and validate the certification path for the complete CRL issuer.
+             If a key usage extension is present in the CRL issuer's certificate,
+             verify that the cRLSign bit is set.
+            
+             @param crl                CRL which contains revocation information for the certificate
+                                       <code>cert</code>.
+             @param cert               The attribute certificate or certificate to check if it is
+                                       revoked.
+             @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+             @param defaultCRLSignKey  The public key of the issuer certificate
+                                       <code>defaultCRLSignCert</code>.
+             @param paramsPKIX         paramsPKIX PKIX parameters.
+             @param certPathCerts      The certificates on the certification path.
+             @return A <code>Set</code> with all keys of possible CRL issuer
+                     certificates.
+             @throws AnnotatedException if the CRL is not valid or the status cannot be checked or
+                                        some error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3280CertPathUtilities.CheckCrl(Org.BouncyCastle.Asn1.X509.DistributionPoint,Org.BouncyCastle.Pkix.PkixParameters,Org.BouncyCastle.X509.X509Certificate,System.DateTime,Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Pkix.CertStatus,Org.BouncyCastle.Pkix.ReasonsMask,System.Collections.IList)">
+             Checks a distribution point for revocation information for the
+             certificate <code>cert</code>.
+            
+             @param dp                 The distribution point to consider.
+             @param paramsPKIX         PKIX parameters.
+             @param cert               Certificate to check if it is revoked.
+             @param validDate          The date when the certificate revocation status should be
+                                       checked.
+             @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+             @param defaultCRLSignKey  The public key of the issuer certificate
+                                       <code>defaultCRLSignCert</code>.
+             @param certStatus         The current certificate revocation status.
+             @param reasonMask         The reasons mask which is already checked.
+             @param certPathCerts      The certificates of the certification path.
+             @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+                                        or some error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3280CertPathUtilities.CheckCrls(Org.BouncyCastle.Pkix.PkixParameters,Org.BouncyCastle.X509.X509Certificate,System.DateTime,Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Collections.IList)">
+             Checks a certificate if it is revoked.
+            
+             @param paramsPKIX       PKIX parameters.
+             @param cert             Certificate to check if it is revoked.
+             @param validDate        The date when the certificate revocation status should be
+                                     checked.
+             @param sign             The issuer certificate of the certificate <code>cert</code>.
+             @param workingPublicKey The public key of the issuer certificate <code>sign</code>.
+             @param certPathCerts    The certificates of the certification path.
+             @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+                                        or some error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3280CertPathUtilities.ProcessCrlC(Org.BouncyCastle.X509.X509Crl,Org.BouncyCastle.X509.X509Crl,Org.BouncyCastle.Pkix.PkixParameters)">
+             If use-deltas is set, verify the issuer and scope of the delta CRL.
+            
+             @param deltaCRL    The delta CRL.
+             @param completeCRL The complete CRL.
+             @param pkixParams  The PKIX paramaters.
+             @throws AnnotatedException if an exception occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3281CertPathUtilities.CheckCrls(Org.BouncyCastle.X509.IX509AttributeCertificate,Org.BouncyCastle.Pkix.PkixParameters,Org.BouncyCastle.X509.X509Certificate,System.DateTime,System.Collections.IList)">
+            Checks if an attribute certificate is revoked.
+            
+            @param attrCert Attribute certificate to check if it is revoked.
+            @param paramsPKIX PKIX parameters.
+            @param issuerCert The issuer certificate of the attribute certificate
+                       <code>attrCert</code>.
+            @param validDate The date when the certificate revocation status should
+                       be checked.
+            @param certPathCerts The certificates of the certification path to be
+                       checked.
+            
+            @throws CertPathValidatorException if the certificate is revoked or the
+                        status cannot be checked or some error occurs.
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3281CertPathUtilities.ProcessAttrCert1(Org.BouncyCastle.X509.IX509AttributeCertificate,Org.BouncyCastle.Pkix.PkixParameters)">
+            Searches for a holder public key certificate and verifies its
+            certification path.
+            
+            @param attrCert the attribute certificate.
+            @param pkixParams The PKIX parameters.
+            @return The certificate path of the holder certificate.
+            @throws Exception if
+                        <ul>
+                        <li>no public key certificate can be found although holder
+                        information is given by an entity name or a base certificate
+                        ID</li>
+                        <li>support classes cannot be created</li>
+                        <li>no certification path for the public key certificate can
+                        be built</li>
+                        </ul>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.Rfc3281CertPathUtilities.CheckCrl(Org.BouncyCastle.Asn1.X509.DistributionPoint,Org.BouncyCastle.X509.IX509AttributeCertificate,Org.BouncyCastle.Pkix.PkixParameters,System.DateTime,Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.Pkix.CertStatus,Org.BouncyCastle.Pkix.ReasonsMask,System.Collections.IList)">
+            
+            Checks a distribution point for revocation information for the
+            certificate <code>attrCert</code>.
+            
+            @param dp The distribution point to consider.
+            @param attrCert The attribute certificate which should be checked.
+            @param paramsPKIX PKIX parameters.
+            @param validDate The date when the certificate revocation status should
+                       be checked.
+            @param issuerCert Certificate to check if it is revoked.
+            @param reasonMask The reasons mask which is already checked.
+            @param certPathCerts The certificates of the certification path to be
+                       checked.
+            @throws Exception if the certificate is revoked or the status
+                        cannot be checked or some error occurs.
+        </member>
+        <member name="T:Org.BouncyCastle.Pkix.TrustAnchor">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.TrustAnchor.#ctor(Org.BouncyCastle.X509.X509Certificate,System.Byte[])">
+             <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="T:System.ArgumentNullException">if the specified X509Certificate is null</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.TrustAnchor.#ctor(Org.BouncyCastle.Asn1.X509.X509Name,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[])">
+            <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="T:System.ArgumentNullException">
+            if <c>caPrincipal</c> or <c>pubKey</c> is null
+            </exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.TrustAnchor.#ctor(System.String,Org.BouncyCastle.Crypto.AsymmetricKeyParameter,System.Byte[])">
+            <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
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.TrustAnchor.setNameConstraints(System.Byte[])">
+            <summary>
+            Decode the name constraints and clone them if not null.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Pkix.TrustAnchor.ToString">
+            <summary>
+            Returns a formatted string describing the <code>TrustAnchor</code>.
+            </summary>
+            <returns>a formatted string describing the <code>TrustAnchor</code></returns>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.TrustAnchor.TrustedCert">
+            <summary>
+            Returns the most-trusted CA certificate.
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.TrustAnchor.CA">
+            <summary>
+            Returns the name of the most-trusted CA as an X509Name.
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.TrustAnchor.CAName">
+            <summary>
+            Returns the name of the most-trusted CA in RFC 2253 string format.
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.Pkix.TrustAnchor.CAPublicKey">
+            <summary>
+            Returns the public key of the most-trusted CA.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Security.AgreementUtilities">
+            <remarks>
+             Utility class for creating IBasicAgreement objects from their names/Oids
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Security.CipherUtilities">
+            <remarks>
+             Cipher Utility class contains methods that can not be specifically grouped into other classes.
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Security.CipherUtilities.GetObjectIdentifier(System.String)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Security.DigestUtilities">
+            <remarks>
+             Utility class for creating IDigest objects from their names/Oids
+            </remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.Security.DigestUtilities.GetObjectIdentifier(System.String)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Security.MacUtilities">
+            <remarks>
+             Utility class for creating HMac object from their names/Oids
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Security.PbeUtilities">
+             <summary>
+            
+             </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Security.PbeUtilities.GetObjectIdentifier(System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Security.SecureRandom.#ctor(Org.BouncyCastle.Crypto.Prng.IRandomGenerator)">
+            <summary>Use the specified instance of IRandomGenerator as random source.</summary>
+            <remarks>
+            This constructor performs no seeding of either the <c>IRandomGenerator</c> or the
+            constructed <c>SecureRandom</c>. It is the responsibility of the client to provide
+            proper seed material as necessary/appropriate for the given <c>IRandomGenerator</c>
+            implementation.
+            </remarks>
+            <param name="generator">The source to generate all random bytes from.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Security.SecurityUtilityException.#ctor">
+            base constructor.
+        </member>
+        <member name="M:Org.BouncyCastle.Security.SecurityUtilityException.#ctor(System.String)">
+             create a SecurityUtilityException with the given message.
+            
+             @param message the message to be carried with the exception.
+        </member>
+        <member name="T:Org.BouncyCastle.Security.SignerUtilities">
+            <summary>
+             Signer Utility class contains methods that can not be specifically grouped into other classes.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Security.SignerUtilities.GetObjectIdentifier(System.String)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Security.WrapperUtilities">
+            <remarks>
+             Utility class for creating IWrapper objects from their names/Oids
+            </remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.Tsp.TimeStampRequest">
+            Base class for an RFC 3161 Time Stamp Request.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequest.#ctor(System.Byte[])">
+             Create a TimeStampRequest from the past in byte array.
+            
+             @param req byte array containing the request.
+             @throws IOException if the request is malformed.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequest.#ctor(System.IO.Stream)">
+             Create a TimeStampRequest from the past in input stream.
+            
+             @param in input stream containing the request.
+             @throws IOException if the request is malformed.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequest.Validate(System.Collections.IList,System.Collections.IList,System.Collections.IList)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequest.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="T:Org.BouncyCastle.Tsp.TimeStampRequestGenerator">
+            Generator for RFC 3161 Time Stamp Request objects.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequestGenerator.AddExtension(System.String,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            add a given extension field for the standard extensions tag (tag 3)
+            @throws IOException
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequestGenerator.AddExtension(System.String,System.Boolean,System.Byte[])">
+            add a given extension field for the standard extensions tag
+            The value parameter becomes the contents of the octet string associated
+            with the extension.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequestGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            add a given extension field for the standard extensions tag (tag 3)
+            @throws IOException
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampRequestGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,System.Byte[])">
+            add a given extension field for the standard extensions tag
+            The value parameter becomes the contents of the octet string associated
+            with the extension.
+        </member>
+        <member name="T:Org.BouncyCastle.Tsp.TimeStampResponse">
+            Base class for an RFC 3161 Time Stamp Response object.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampResponse.#ctor(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampResponse.#ctor(System.IO.Stream)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampResponse.Validate(Org.BouncyCastle.Tsp.TimeStampRequest)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampResponse.GetEncoded">
+            return the ASN.1 encoded representation of this object.
+        </member>
+        <member name="T:Org.BouncyCastle.Tsp.TimeStampResponseGenerator">
+            Generator for RFC 3161 Time Stamp Responses.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampResponseGenerator.Generate(Org.BouncyCastle.Tsp.TimeStampRequest,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Utilities.Date.DateTimeObject)">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampResponseGenerator.GenerateFailResponse(Org.BouncyCastle.Asn1.Cmp.PkiStatus,System.Int32,System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampToken.Validate(Org.BouncyCastle.X509.X509Certificate)">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampToken.ToCmsSignedData">
+             Return the underlying CmsSignedData object.
+            
+             @return the underlying CMS structure.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampToken.GetEncoded">
+             Return a ASN.1 encoded byte stream representing the encoded object.
+            
+             @throws IOException if encoding fails.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampTokenGenerator.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String)">
+            basic creation - only the default attributes will be included here.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TimeStampTokenGenerator.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.X509.X509Certificate,System.String,System.String,Org.BouncyCastle.Asn1.Cms.AttributeTable,Org.BouncyCastle.Asn1.Cms.AttributeTable)">
+            create with a signer with extra signed/unsigned attributes.
+        </member>
+        <member name="P:Org.BouncyCastle.Tsp.TimeStampTokenInfo.Nonce">
+            @return the nonce value, null if there isn't one.
+        </member>
+        <member name="T:Org.BouncyCastle.Tsp.TspAlgorithms">
+            Recognised hash algorithms for the time stamp protocol.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TspUtil.GetSignatureTimestamps(Org.BouncyCastle.Cms.SignerInformation)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TspUtil.ValidateCertificate(Org.BouncyCastle.X509.X509Certificate)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Tsp.TspUtil.GetDigestAlgName(System.String)">
+            <summary>
+            Return the digest algorithm using one of the standard JCA string
+            representations rather than the algorithm identifier (if possible).
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Tsp.TspValidationException">
+            Exception thrown if a TSP request or response fails to validate.
+            <p>
+            If a failure code is associated with the exception it can be retrieved using
+            the getFailureCode() method.</p>
+        </member>
+        <member name="P:Org.BouncyCastle.Tsp.TspValidationException.FailureCode">
+             Return the failure code associated with this exception - if one is set.
+            
+             @return the failure code if set, -1 otherwise.
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Arrays">
+            <summary> General array utilities.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Arrays.AreEqual(System.Byte[],System.Byte[])">
+            <summary>
+            Are two arrays equal.
+            </summary>
+            <param name="a">Left side.</param>
+            <param name="b">Right side.</param>
+            <returns>True if equal.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Arrays.ConstantTimeAreEqual(System.Byte[],System.Byte[])">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.BigIntegers">
+            BigInteger utilities.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.BigIntegers.AsUnsignedByteArray(Org.BouncyCastle.Math.BigInteger)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.BigIntegers.CreateRandomInRange(Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Math.BigInteger,Org.BouncyCastle.Security.SecureRandom)">
+            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]
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Date.DateTimeUtilities.DateTimeToUnixMs(System.DateTime)">
+            <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="T:System.ArgumentException">'dateTime' is before epoch.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Date.DateTimeUtilities.UnixMsToDateTime(System.Int64)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Date.DateTimeUtilities.CurrentUnixMs">
+            <summary>
+            Return the current number of milliseconds since the Unix epoch (1 Jan., 1970 UTC).
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64.Encode(System.Byte[])">
+             encode the input data producing a base 64 encoded byte array.
+            
+             @return a byte array containing the base 64 encoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64.Encode(System.Byte[],System.IO.Stream)">
+             Encode the byte data to base 64 writing it to the given output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64.Encode(System.Byte[],System.Int32,System.Int32,System.IO.Stream)">
+             Encode the byte data to base 64 writing it to the given output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64.Decode(System.Byte[])">
+             decode the base 64 encoded input data. It is assumed the input data is valid.
+            
+             @return a byte array representing the decoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64.Decode(System.String)">
+             decode the base 64 encoded string data - whitespace will be ignored.
+            
+             @return a byte array representing the decoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64.Decode(System.String,System.IO.Stream)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.IEncoder">
+            Encode and decode byte arrays (typically from binary to 7-bit ASCII
+            encodings).
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64Encoder.Encode(System.Byte[],System.Int32,System.Int32,System.IO.Stream)">
+             encode the input data producing a base 64 output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64Encoder.Decode(System.Byte[],System.Int32,System.Int32,System.IO.Stream)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Base64Encoder.DecodeString(System.String,System.IO.Stream)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.BufferedDecoder">
+            <summary>
+             A buffering class to allow translation from one format to another to
+                be done in discrete chunks.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.BufferedDecoder.#ctor(Org.BouncyCastle.Utilities.Encoders.ITranslator,System.Int32)">
+            <summary>
+            Create a buffered Decoder.
+            </summary>
+            <param name="translator">The translater to use.</param>
+            <param name="bufferSize">The size of the buffer.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.BufferedDecoder.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.BufferedDecoder.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.BufferedEncoder">
+            <summary>
+            A class that allows encoding of data using a specific encoder to be processed in chunks.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.BufferedEncoder.#ctor(Org.BouncyCastle.Utilities.Encoders.ITranslator,System.Int32)">
+            <summary>
+            Create.
+            </summary>
+            <param name="translator">The translator to use.</param>
+            <param name="bufferSize">Size of the chunks.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.BufferedEncoder.ProcessByte(System.Byte,System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.BufferedEncoder.ProcessBytes(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.Hex">
+            <summary>
+            Class to decode and encode Hex.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Encode(System.Byte[])">
+             encode the input data producing a Hex encoded byte array.
+            
+             @return a byte array containing the Hex encoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Encode(System.Byte[],System.Int32,System.Int32)">
+             encode the input data producing a Hex encoded byte array.
+            
+             @return a byte array containing the Hex encoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Encode(System.Byte[],System.IO.Stream)">
+             Hex encode the byte data writing it to the given output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Encode(System.Byte[],System.Int32,System.Int32,System.IO.Stream)">
+             Hex encode the byte data writing it to the given output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Decode(System.Byte[])">
+             decode the Hex encoded input data. It is assumed the input data is valid.
+            
+             @return a byte array representing the decoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Decode(System.String)">
+             decode the Hex encoded string data - whitespace will be ignored.
+            
+             @return a byte array representing the decoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.Hex.Decode(System.String,System.IO.Stream)">
+             decode the Hex encoded string data writing it to the given output stream,
+             whitespace characters will be ignored.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexEncoder.Encode(System.Byte[],System.Int32,System.Int32,System.IO.Stream)">
+             encode the input data producing a Hex output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexEncoder.Decode(System.Byte[],System.Int32,System.Int32,System.IO.Stream)">
+             decode the Hex encoded byte data writing it to the given output stream,
+             whitespace characters will be ignored.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexEncoder.DecodeString(System.String,System.IO.Stream)">
+             decode the Hex encoded string data writing it to the given output stream,
+             whitespace characters will be ignored.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.HexTranslator">
+            <summary>
+            A hex translator.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.ITranslator">
+            <summary>
+            Translator interface.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexTranslator.GetEncodedBlockSize">
+            <summary>
+            Return encoded block size.
+            </summary>
+            <returns>2</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexTranslator.Encode(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexTranslator.GetDecodedBlockSize">
+            <summary>
+            Returns the decoded block size.
+            </summary>
+            <returns>1</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.HexTranslator.Decode(System.Byte[],System.Int32,System.Int32,System.Byte[],System.Int32)">
+            <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>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.UrlBase64">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.UrlBase64.Encode(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.UrlBase64.Encode(System.Byte[],System.IO.Stream)">
+             Encode the byte data writing it to the given output stream.
+            
+             @return the number of bytes produced.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.UrlBase64.Decode(System.Byte[])">
+             Decode the URL safe base 64 encoded input data - white space will be ignored.
+            
+             @return a byte array representing the decoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.UrlBase64.Decode(System.Byte[],System.IO.Stream)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.UrlBase64.Decode(System.String)">
+             decode the URL safe base 64 encoded string data - whitespace will be ignored.
+            
+             @return a byte array representing the decoded data.
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Encoders.UrlBase64.Decode(System.String,System.IO.Stream)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Encoders.UrlBase64Encoder">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.IO.Pem.PemObjectParser.ParseObject(Org.BouncyCastle.Utilities.IO.Pem.PemObject)">
+            <param name="obj">
+            A <see cref="T:Org.BouncyCastle.Utilities.IO.Pem.PemObject"/>
+            </param>
+            <returns>
+            A <see cref="T:System.Object"/>
+            </returns>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.IO.Streams.PipeAllLimited(System.IO.Stream,System.Int64,System.IO.Stream)">
+            <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="T:System.IO.Stream"/>
+            </param>
+            <param name="limit">
+            A <see cref="T:System.Int64"/>
+            </param>
+            <param name="outStr">
+            A <see cref="T:System.IO.Stream"/>
+            </param>
+            <returns>The number of bytes actually transferred, if not greater than <c>limit</c></returns>
+            <exception cref="T:System.IO.IOException"></exception>
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Net.IPAddress.IsValid(System.String)">
+             Validate the given IPv4 or IPv6 address.
+            
+             @param address the IP address as a string.
+            
+             @return true if a valid address, false otherwise
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Net.IPAddress.IsValidWithNetMask(System.String)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Net.IPAddress.IsValidIPv4(System.String)">
+             Validate the given IPv4 address.
+             
+             @param address the IP address as a string.
+            
+             @return true if a valid IPv4 address, false otherwise
+        </member>
+        <member name="M:Org.BouncyCastle.Utilities.Net.IPAddress.IsValidIPv6(System.String)">
+             Validate the given IPv6 address.
+            
+             @param address the IP address as a string.
+            
+             @return true if a valid IPv4 address, false otherwise
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Strings">
+            <summary> General string utilities.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Zlib.ZDeflaterOutputStream">
+            <summary>
+            Summary description for DeflaterOutputStream.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.Utilities.Zlib.ZInflaterInputStream">
+            <summary>
+            Summary description for DeflaterOutputStream.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.AttributeCertificateHolder">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.AttributeCertificateHolder.#ctor(System.Int32,System.String,System.String,System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.AttributeCertificateHolder.GetObjectDigest">
+             Returns the hash if an object digest info is used.
+            
+             @return The hash or <code>null</code> if no object digest info is set.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.AttributeCertificateHolder.GetEntityNames">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.AttributeCertificateHolder.GetIssuer">
+             Return the principals associated with the issuer attached to this holder
+            
+             @return an array of principals, null if no BaseCertificateID is set.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.AttributeCertificateHolder.DigestedObjectType">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.AttributeCertificateHolder.DigestAlgorithm">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.AttributeCertificateHolder.OtherObjectTypeID">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.AttributeCertificateHolder.SerialNumber">
+             Return the serial number associated with the issuer attached to this holder.
+            
+             @return the certificate serial number, null if no BaseCertificateID is set.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.AttributeCertificateIssuer">
+            Carrying class for an attribute certificate issuer.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.AttributeCertificateIssuer.#ctor(Org.BouncyCastle.Asn1.X509.AttCertIssuer)">
+             Set the issuer directly with the ASN.1 structure.
+            
+             @param issuer The issuer
+        </member>
+        <member name="M:Org.BouncyCastle.X509.AttributeCertificateIssuer.GetPrincipals">
+            <summary>Return any principal objects inside the attribute certificate issuer object.</summary>
+            <returns>An array of IPrincipal objects (usually X509Principal).</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.Extension.AuthorityKeyIdentifierStructure">
+            <remarks>A high level authority key identifier.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Extension.AuthorityKeyIdentifierStructure.#ctor(Org.BouncyCastle.Asn1.Asn1OctetString)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Extension.AuthorityKeyIdentifierStructure.#ctor(Org.BouncyCastle.X509.X509Certificate)">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Extension.AuthorityKeyIdentifierStructure.#ctor(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.Extension.SubjectKeyIdentifierStructure">
+            A high level subject key identifier.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Extension.SubjectKeyIdentifierStructure.#ctor(Org.BouncyCastle.Asn1.Asn1OctetString)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.IX509AttributeCertificate">
+            <remarks>Interface for an X.509 Attribute Certificate.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.IX509AttributeCertificate.GetAttributes">
+            <summary>Return the attributes contained in the attribute block in the certificate.</summary>
+            <returns>An array of attributes.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.IX509AttributeCertificate.GetAttributes(System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.IX509AttributeCertificate.GetEncoded">
+            <summary>Return an ASN.1 encoded byte array representing the attribute certificate.</summary>
+            <returns>An ASN.1 encoded byte array.</returns>
+            <exception cref="T:System.IO.IOException">If the certificate cannot be encoded.</exception>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.IX509AttributeCertificate.Version">
+            <summary>The version number for the certificate.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.IX509AttributeCertificate.SerialNumber">
+            <summary>The serial number for the certificate.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.IX509AttributeCertificate.NotBefore">
+            <summary>The UTC DateTime before which the certificate is not valid.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.IX509AttributeCertificate.NotAfter">
+            <summary>The UTC DateTime after which the certificate is not valid.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.IX509AttributeCertificate.Holder">
+            <summary>The holder of the certificate.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.IX509AttributeCertificate.Issuer">
+            <summary>The issuer details for the certificate.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.PrincipalUtilities">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.PrincipalUtilities.GetIssuerX509Principal(Org.BouncyCastle.X509.X509Certificate)">
+            <summary>Return the issuer of the given cert as an X509Principal.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.PrincipalUtilities.GetSubjectX509Principal(Org.BouncyCastle.X509.X509Certificate)">
+            <summary>Return the subject of the given cert as an X509Principal.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.PrincipalUtilities.GetIssuerX509Principal(Org.BouncyCastle.X509.X509Crl)">
+            <summary>Return the issuer of the given CRL as an X509Principal.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector">
+             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
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.Match(System.Object)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.AddTargetName(Org.BouncyCastle.Asn1.X509.GeneralName)">
+             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>)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.AddTargetName(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.SetTargetNames(System.Collections.IEnumerable)">
+            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)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.GetTargetNames">
+            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)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.AddTargetGroup(Org.BouncyCastle.Asn1.X509.GeneralName)">
+             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>)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.AddTargetGroup(System.Byte[])">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.SetTargetGroups(System.Collections.IEnumerable)">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.GetTargetGroups">
+             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)
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.AttributeCert">
+            <summary>The attribute certificate which must be matched.</summary>
+            <remarks>If <c>null</c> is given, any will do.</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.AttributeCertificateValid">
+            <summary>The criteria for validity</summary>
+            <remarks>If <c>null</c> is given any will do.</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.Holder">
+            <summary>The holder.</summary>
+            <remarks>If <c>null</c> is given any will do.</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.Issuer">
+            <summary>The issuer.</summary>
+            <remarks>If <c>null</c> is given any will do.</remarks>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509AttrCertStoreSelector.SerialNumber">
+            <summary>The serial number.</summary>
+            <remarks>If <c>null</c> is given any will do.</remarks>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.Store.X509CertPairStoreSelector">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509CertPairStoreSelector.Match(System.Object)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CertPairStoreSelector.CertPair">
+            <summary>The certificate pair which is used for testing on equality.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CertPairStoreSelector.ForwardSelector">
+            <summary>The certificate selector for the forward part.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CertPairStoreSelector.ReverseSelector">
+            <summary>The certificate selector for the reverse part.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.Store.X509CollectionStore">
+            A simple collection backed store.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509CollectionStore.#ctor(System.Collections.ICollection)">
+             Basic constructor.
+            
+             @param collection - initial contents for the store, this is copied.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509CollectionStore.GetMatches(Org.BouncyCastle.X509.Store.IX509Selector)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.Store.X509CollectionStoreParameters">
+            <remarks>This class contains a collection for collection based <code>X509Store</code>s.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509CollectionStoreParameters.#ctor(System.Collections.ICollection)">
+            <summary>
+            Constructor.
+            <p>
+            The collection is copied.
+            </p>
+            </summary>
+            <param name="collection">The collection containing X.509 object types.</param>
+            <exception cref="T:System.ArgumentNullException">If collection is null.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509CollectionStoreParameters.GetCollection">
+            <summary>Returns a copy of the <code>ICollection</code>.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.Store.X509CollectionStoreParameters.ToString">
+            <summary>Returns a formatted string describing the parameters.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.Issuers">
+            <summary>
+            An <code>ICollection</code> of <code>X509Name</code> objects
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.AttrCertChecking">
+             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()
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.CompleteCrlEnabled">
+             If <code>true</code> only complete CRLs are returned. Defaults to
+             <code>false</code>.
+            
+             @return <code>true</code> if only complete CRLs are returned.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.DeltaCrlIndicatorEnabled">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.IssuingDistributionPoint">
+             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()
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.IssuingDistributionPointEnabled">
+             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.
+        </member>
+        <member name="P:Org.BouncyCastle.X509.Store.X509CrlStoreSelector.MaxBaseCrlNumber">
+             The maximum base CRL number. Defaults to <code>null</code>.
+            
+             @return Returns the maximum base CRL number.
+             @see #setMaxBaseCRLNumber(BigInteger)
+        </member>
+        <member name="T:Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory">
+            <summary>
+            A factory to produce Public Key Info Objects.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <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="T:System.Exception">Throw exception if object provided is not one of the above.</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509AttrCertParser.ReadAttrCert(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509AttrCertParser.ReadAttrCerts(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509AttrCertParser.ReadAttrCert(System.IO.Stream)">
+            Generates a certificate object and initializes it with the data
+            read from the input stream inStream.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509AttrCertParser.ReadAttrCerts(System.IO.Stream)">
+            Returns a (possibly empty) collection view of the certificates
+            read from the given input stream inStream.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509Attribute">
+            Class for carrying the values in an X.509 Attribute.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Attribute.#ctor(Org.BouncyCastle.Asn1.Asn1Encodable)">
+            @param at an object representing an attribute.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Attribute.#ctor(System.String,Org.BouncyCastle.Asn1.Asn1Encodable)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Attribute.#ctor(System.String,Org.BouncyCastle.Asn1.Asn1EncodableVector)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509Certificate">
+            <summary>
+            An Object representing an X509 Certificate.
+            Has static methods for loading Certificates encoded in many forms that return X509Certificate Objects.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.IsValid(System.DateTime)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.CheckValidity">
+            <summary>
+            Checks if the current date is within certificate's validity period.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.CheckValidity(System.DateTime)">
+            <summary>
+            Checks if the given date is within certificate's validity period.
+            </summary>
+            <exception cref="T:Org.BouncyCastle.Security.Certificates.CertificateExpiredException">if the certificate is expired by given date</exception>
+            <exception cref="T:Org.BouncyCastle.Security.Certificates.CertificateNotYetValidException">if the certificate is not yet valid on given date</exception>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.GetTbsCertificate">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.GetSignature">
+            <summary>
+            The signature.
+            </summary>
+            <returns>A byte array containg the signature of the certificate.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.GetSigAlgParams">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.GetKeyUsage">
+            <summary>
+            Get a key usage guidlines.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.GetPublicKey">
+            <summary>
+            Get the public key of the subject of the certificate.
+            </summary>
+            <returns>The public key parameters.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.GetEncoded">
+            <summary>
+            Return a Der encoded version of this certificate.
+            </summary>
+            <returns>A byte array.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Certificate.Verify(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <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="T:System.Exception">If key submitted is not of the above nominated types.</exception>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.IsValidNow">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.Version">
+            <summary>
+            Return the certificate's version.
+            </summary>
+            <returns>An integer whose value Equals the version of the cerficate.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.SerialNumber">
+            <summary>
+            Return a <see cref="T:Org.BouncyCastle.Math.BigInteger">BigInteger</see> containing the serial number.
+            </summary>
+            <returns>The Serial number.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.IssuerDN">
+            <summary>
+            Get the Issuer Distinguished Name. (Who signed the certificate.)
+            </summary>
+            <returns>And X509Object containing name and value pairs.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.SubjectDN">
+            <summary>
+            Get the subject of this certificate.
+            </summary>
+            <returns>An X509Name object containing name and value pairs.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.NotBefore">
+            <summary>
+            The time that this certificate is valid from.
+            </summary>
+            <returns>A DateTime object representing that time in the local time zone.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.NotAfter">
+            <summary>
+            The time that this certificate is valid up to.
+            </summary>
+            <returns>A DateTime object representing that time in the local time zone.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.SigAlgName">
+            <summary>
+            A meaningful version of the Signature Algorithm. (EG SHA1WITHRSA)
+            </summary>
+            <returns>A sting representing the signature algorithm.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.SigAlgOid">
+            <summary>
+            Get the Signature Algorithms Object ID.
+            </summary>
+            <returns>A string containg a '.' separated object id.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.IssuerUniqueID">
+            <summary>
+            Get the issuers UID.
+            </summary>
+            <returns>A DerBitString.</returns>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509Certificate.SubjectUniqueID">
+            <summary>
+            Get the subjects UID.
+            </summary>
+            <returns>A DerBitString.</returns>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509CertificatePair">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertificatePair.#ctor(Org.BouncyCastle.X509.X509Certificate,Org.BouncyCastle.X509.X509Certificate)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertificatePair.#ctor(Org.BouncyCastle.Asn1.X509.CertificatePair)">
+            <summary>Constructor from a ASN.1 CertificatePair structure.</summary>
+            <param name="pair">The <c>CertificatePair</c> ASN.1 object.</param>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509CertificatePair.Forward">
+            <summary>Returns the certificate from the other CA to this CA.</summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509CertificatePair.Reverse">
+            <summary>Returns the certificate from this CA to the other CA.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509CertificateParser">
+            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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertificateParser.ReadCertificate(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertificateParser.ReadCertificates(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertificateParser.ReadCertificate(System.IO.Stream)">
+            Generates a certificate object and initializes it with the data
+            read from the input stream inStream.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertificateParser.ReadCertificates(System.IO.Stream)">
+            Returns a (possibly empty) collection view of the certificates
+            read from the given input stream inStream.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertPairParser.ReadCertPair(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CertPairParser.ReadCertPairs(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509Crl">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Crl.ToString">
+             Returns a string representation of this CRL.
+            
+             @return a string representation of this CRL.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509Crl.IsRevoked(Org.BouncyCastle.X509.X509Certificate)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509CrlEntry">
+             The following extensions are listed in RFC 2459 as relevant to CRL Entries
+            
+             ReasonCode Hode Instruction Code Invalidity Date Certificate Issuer
+             (critical)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CrlEntry.#ctor(Org.BouncyCastle.Asn1.X509.CrlEntry,System.Boolean,Org.BouncyCastle.Asn1.X509.X509Name)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CrlParser.ReadCrl(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CrlParser.ReadCrls(System.Byte[])">
+            <summary>
+            Create loading data from byte array.
+            </summary>
+            <param name="input"></param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CrlParser.ReadCrl(System.IO.Stream)">
+            Generates a certificate revocation list (CRL) object and initializes
+            it with the data read from the input stream inStream.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509CrlParser.ReadCrls(System.IO.Stream)">
+             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.
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509KeyUsage">
+             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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509KeyUsage.#ctor(System.Int32)">
+             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)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509SignatureUtilities.GetDigestAlgName(Org.BouncyCastle.Asn1.DerObjectIdentifier)">
+            Return the digest algorithm using one of the standard JCA string
+            representations rather than the algorithm identifier (if possible).
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509V1CertificateGenerator">
+            <summary>
+            Class to Generate X509V1 Certificates.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.#ctor">
+            <summary>
+            Default Constructor.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.Reset">
+            <summary>
+            Reset the generator.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetSerialNumber(Org.BouncyCastle.Math.BigInteger)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetIssuerDN(Org.BouncyCastle.Asn1.X509.X509Name)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetNotBefore(System.DateTime)">
+            <summary>
+            Set the date that this certificate is to be valid from.
+            </summary>
+            <param name="date"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetNotAfter(System.DateTime)">
+            <summary>
+            Set the date after which this certificate will no longer be valid.
+            </summary>
+            <param name="date"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetSubjectDN(Org.BouncyCastle.Asn1.X509.X509Name)">
+            <summary>
+            Set the subject distinguished name.
+            The subject describes the entity associated with the public key.
+            </summary>
+            <param name="subject"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetPublicKey(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <summary>
+            Set the public key that this certificate identifies.
+            </summary>
+            <param name="publicKey"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.SetSignatureAlgorithm(System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V1CertificateGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509V1CertificateGenerator.SignatureAlgNames">
+            <summary>
+            Allows enumeration of the signature names supported by the generator.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509V2AttributeCertificate">
+            <summary>An implementation of a version 2 X.509 Attribute Certificate.</summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator">
+            <remarks>Class to produce an X.509 Version 2 AttributeCertificate.</remarks>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.Reset">
+            <summary>Reset the generator</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.SetHolder(Org.BouncyCastle.X509.AttributeCertificateHolder)">
+            <summary>Set the Holder of this Attribute Certificate.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.SetIssuer(Org.BouncyCastle.X509.AttributeCertificateIssuer)">
+            <summary>Set the issuer.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.SetSerialNumber(Org.BouncyCastle.Math.BigInteger)">
+            <summary>Set the serial number for the certificate.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.SetSignatureAlgorithm(System.String)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.AddAttribute(Org.BouncyCastle.X509.X509Attribute)">
+            <summary>Add an attribute.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.AddExtension(System.String,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            <summary>Add a given extension field for the standard extensions tag.</summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.AddExtension(System.String,System.Boolean,System.Byte[])">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <summary>
+            Generate an X509 certificate, based on the current issuer and subject.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Security.SecureRandom)">
+            <summary>
+            Generate an X509 certificate, based on the current issuer and subject,
+            using the supplied source of randomness, if required.
+            </summary>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509V2AttributeCertificateGenerator.SignatureAlgNames">
+            <summary>
+            Allows enumeration of the signature names supported by the generator.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509V2CrlGenerator">
+            class to produce an X.509 Version 2 CRL.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.Reset">
+            reset the generator
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.SetIssuerDN(Org.BouncyCastle.Asn1.X509.X509Name)">
+            Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
+            certificate.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddCrlEntry(Org.BouncyCastle.Math.BigInteger,System.DateTime,System.Int32)">
+             Reason being as indicated by CrlReason, i.e. CrlReason.KeyCompromise
+             or 0 if CrlReason is not to be used
+            
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddCrlEntry(Org.BouncyCastle.Math.BigInteger,System.DateTime,System.Int32,System.DateTime)">
+             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
+            
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddCrlEntry(Org.BouncyCastle.Math.BigInteger,System.DateTime,Org.BouncyCastle.Asn1.X509.X509Extensions)">
+             Add a CRL entry with extensions.
+            
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddCrl(Org.BouncyCastle.X509.X509Crl)">
+             Add the CRLEntry objects contained in a previous CRL.
+            
+             @param other the X509Crl to source the other entries from.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.SetSignatureAlgorithm(System.String)">
+             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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddExtension(System.String,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            add a given extension field for the standard extensions tag (tag 0)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            add a given extension field for the standard extensions tag (tag 0)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddExtension(System.String,System.Boolean,System.Byte[])">
+            add a given extension field for the standard extensions tag (tag 0)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,System.Byte[])">
+            add a given extension field for the standard extensions tag (tag 0)
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <summary>Generate an X509 CRL, based on the current issuer and subject.</summary>
+            <param name="privateKey">The key used for signing.</param>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V2CrlGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509V2CrlGenerator.SignatureAlgNames">
+            <summary>
+            Allows enumeration of the signature names supported by the generator.
+            </summary>
+        </member>
+        <member name="T:Org.BouncyCastle.X509.X509V3CertificateGenerator">
+            <summary>
+            A class to Generate Version 3 X509Certificates.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.Reset">
+            <summary>
+            Reset the Generator.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetSerialNumber(Org.BouncyCastle.Math.BigInteger)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetIssuerDN(Org.BouncyCastle.Asn1.X509.X509Name)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetNotBefore(System.DateTime)">
+            <summary>
+            Set the date that this certificate is to be valid from.
+            </summary>
+            <param name="date"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetNotAfter(System.DateTime)">
+            <summary>
+            Set the date after which this certificate will no longer be valid.
+            </summary>
+            <param name="date"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetSubjectDN(Org.BouncyCastle.Asn1.X509.X509Name)">
+            <summary>
+            Set the DN of the entity that this certificate is about.
+            </summary>
+            <param name="subject"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetPublicKey(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <summary>
+            Set the public key that this certificate identifies.
+            </summary>
+            <param name="publicKey"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetSignatureAlgorithm(System.String)">
+            <summary>
+            Set the signature algorithm that will be used to sign this certificate.
+            </summary>
+            <param name="signatureAlgorithm"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetSubjectUniqueID(System.Boolean[])">
+            <summary>
+            Set the subject unique ID - note: it is very rare that it is correct to do this.
+            </summary>
+            <param name="uniqueID"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.SetIssuerUniqueID(System.Boolean[])">
+            <summary>
+            Set the issuer unique ID - note: it is very rare that it is correct to do this.
+            </summary>
+            <param name="uniqueID"/>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.AddExtension(System.String,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,Org.BouncyCastle.Asn1.Asn1Encodable)">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.AddExtension(System.String,System.Boolean,System.Byte[])">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.AddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,System.Byte[])">
+            <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>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.CopyAndAddExtension(System.String,System.Boolean,Org.BouncyCastle.X509.X509Certificate)">
+            <summary>
+            Add a given extension field for the standard extensions tag (tag 3),
+            copying the extension value from another certificate.
+            </summary>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.CopyAndAddExtension(Org.BouncyCastle.Asn1.DerObjectIdentifier,System.Boolean,Org.BouncyCastle.X509.X509Certificate)">
+            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.
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter)">
+            <summary>
+            Generate an X509Certificate.
+            </summary>
+            <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
+            <returns>An X509Certificate.</returns>
+        </member>
+        <member name="M:Org.BouncyCastle.X509.X509V3CertificateGenerator.Generate(Org.BouncyCastle.Crypto.AsymmetricKeyParameter,Org.BouncyCastle.Security.SecureRandom)">
+            <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>
+        </member>
+        <member name="P:Org.BouncyCastle.X509.X509V3CertificateGenerator.SignatureAlgNames">
+            <summary>
+            Allows enumeration of the signature names supported by the generator.
+            </summary>
+        </member>
+    </members>
+</doc>
diff --git a/Crypto/src/AssemblyInfo.cs b/Crypto/src/AssemblyInfo.cs
new file mode 100644
index 000000000..7064bf82e
--- /dev/null
+++ b/Crypto/src/AssemblyInfo.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+//using System.Security.Permissions;
+
+//
+// General Information about an assembly is controlled through the following
+// 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: AssemblyProduct("Bouncy Castle for .NET")]
+[assembly: AssemblyCopyright("Copyright (C) 2000-2011")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+
+[assembly: AssemblyVersion(AssemblyInfo.Version)]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+//   (*) If no key is specified, the assembly is not signed.
+//   (*) KeyName refers to a key that has been installed in the Crypto Service
+//       Provider (CSP) on your machine. KeyFile refers to a file which contains
+//       a key.
+//   (*) If the KeyFile and the KeyName values are both specified, the
+//       following processing occurs:
+//       (1) If the KeyName can be found in the CSP, that key is used.
+//       (2) If the KeyName does not exist and the KeyFile does exist, the key
+//           in the KeyFile is installed into the CSP and used.
+//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+//       When specifying the KeyFile, the location of the KeyFile should be
+//       relative to the project output directory which is
+//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+//       located in the project directory, you would specify the AssemblyKeyFile
+//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+//       documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+#if STRONG_NAME
+[assembly: AssemblyKeyFile(@"../BouncyCastle.snk")]
+#else
+[assembly: AssemblyKeyFile("")]
+#endif
+[assembly: AssemblyKeyName("")]
+
+[assembly: CLSCompliant(true)]
+
+// Start with no permissions
+//[assembly: PermissionSet(SecurityAction.RequestOptional, Unrestricted=false)]
+//...and explicitly add those we need
+
+// 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
new file mode 100644
index 000000000..6c256db53
--- /dev/null
+++ b/Crypto/src/asn1/ASN1StreamParser.cs
@@ -0,0 +1,232 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class Asn1StreamParser
+	{
+		private readonly Stream _in;
+		private readonly int _limit;
+
+		public Asn1StreamParser(
+			Stream inStream)
+			: this(inStream, Asn1InputStream.FindLimit(inStream))
+		{
+		}
+
+		public Asn1StreamParser(
+			Stream	inStream,
+			int		limit)
+		{
+			if (!inStream.CanRead)
+				throw new ArgumentException("Expected stream to be readable", "inStream");
+
+			this._in = inStream;
+			this._limit = limit;
+		}
+
+		public Asn1StreamParser(
+			byte[] encoding)
+			: this(new MemoryStream(encoding, false), encoding.Length)
+		{
+		}
+
+		internal IAsn1Convertible ReadIndef(int tagValue)
+		{
+			// Note: INDEF => CONSTRUCTED
+
+			// TODO There are other tags that may be constructed (e.g. BIT_STRING)
+			switch (tagValue)
+			{
+				case Asn1Tags.External:
+					return new DerExternalParser(this);
+				case Asn1Tags.OctetString:
+					return new BerOctetStringParser(this);
+				case Asn1Tags.Sequence:
+					return new BerSequenceParser(this);
+				case Asn1Tags.Set:
+					return new BerSetParser(this);
+				default:
+					throw new Asn1Exception("unknown BER object encountered: 0x" + tagValue.ToString("X"));
+			}
+		}
+
+		internal IAsn1Convertible ReadImplicit(bool constructed, int tag)
+		{
+			if (_in is IndefiniteLengthInputStream)
+			{
+				if (!constructed)
+					throw new IOException("indefinite length primitive encoding encountered");
+
+				return ReadIndef(tag);
+			}
+
+			if (constructed)
+			{
+				switch (tag)
+				{
+					case Asn1Tags.Set:
+						return new DerSetParser(this);
+					case Asn1Tags.Sequence:
+						return new DerSequenceParser(this);
+					case Asn1Tags.OctetString:
+						return new BerOctetStringParser(this);
+				}
+			}
+			else
+			{
+				switch (tag)
+				{
+					case Asn1Tags.Set:
+						throw new Asn1Exception("sequences must use constructed encoding (see X.690 8.9.1/8.10.1)");
+					case Asn1Tags.Sequence:
+						throw new Asn1Exception("sets must use constructed encoding (see X.690 8.11.1/8.12.1)");
+					case Asn1Tags.OctetString:
+						return new DerOctetStringParser((DefiniteLengthInputStream)_in);
+				}
+			}
+
+			throw new Asn1Exception("implicit tagging not implemented");
+		}
+
+		internal Asn1Object ReadTaggedObject(bool constructed, int tag)
+		{
+			if (!constructed)
+			{
+				// Note: !CONSTRUCTED => IMPLICIT
+				DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in;
+				return new DerTaggedObject(false, tag, new DerOctetString(defIn.ToArray()));
+			}
+
+			Asn1EncodableVector v = ReadVector();
+
+			if (_in is IndefiniteLengthInputStream)
+			{
+				return v.Count == 1
+					?   new BerTaggedObject(true, tag, v[0])
+					:   new BerTaggedObject(false, tag, BerSequence.FromVector(v));
+			}
+
+			return v.Count == 1
+				?   new DerTaggedObject(true, tag, v[0])
+				:   new DerTaggedObject(false, tag, DerSequence.FromVector(v));
+		}
+
+		public virtual IAsn1Convertible ReadObject()
+		{
+			int tag = _in.ReadByte();
+			if (tag == -1)
+				return null;
+
+			// turn of looking for "00" while we resolve the tag
+			Set00Check(false);
+
+			//
+			// calculate tag number
+			//
+			int tagNo = Asn1InputStream.ReadTagNumber(_in, tag);
+
+			bool isConstructed = (tag & Asn1Tags.Constructed) != 0;
+
+			//
+			// calculate length
+			//
+			int length = Asn1InputStream.ReadLength(_in, _limit);
+
+			if (length < 0) // indefinite length method
+			{
+				if (!isConstructed)
+					throw new IOException("indefinite length primitive encoding encountered");
+
+				IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in, _limit);
+				Asn1StreamParser sp = new Asn1StreamParser(indIn, _limit);
+
+				if ((tag & Asn1Tags.Application) != 0)
+				{
+					return new BerApplicationSpecificParser(tagNo, sp);
+				}
+
+				if ((tag & Asn1Tags.Tagged) != 0)
+				{
+					return new BerTaggedObjectParser(true, tagNo, sp);
+				}
+
+				return sp.ReadIndef(tagNo);
+			}
+			else
+			{
+				DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
+
+				if ((tag & Asn1Tags.Application) != 0)
+				{
+					return new DerApplicationSpecific(isConstructed, tagNo, defIn.ToArray());
+				}
+
+				if ((tag & Asn1Tags.Tagged) != 0)
+				{
+					return new BerTaggedObjectParser(isConstructed, tagNo, new Asn1StreamParser(defIn));
+				}
+
+				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 BerOctetStringParser(new Asn1StreamParser(defIn));
+						case Asn1Tags.Sequence:
+							return new DerSequenceParser(new Asn1StreamParser(defIn));
+						case Asn1Tags.Set:
+							return new DerSetParser(new Asn1StreamParser(defIn));
+						case Asn1Tags.External:
+							return new DerExternalParser(new Asn1StreamParser(defIn));
+						default:
+							// TODO Add DerUnknownTagParser class?
+							return new DerUnknownTag(true, tagNo, defIn.ToArray());
+					}
+				}
+
+				// Some primitive encodings can be handled by parsers too...
+				switch (tagNo)
+				{
+					case Asn1Tags.OctetString:
+						return new DerOctetStringParser(defIn);
+				}
+
+				try
+				{
+					return Asn1InputStream.CreatePrimitiveDerObject(tagNo, defIn.ToArray());
+				}
+				catch (ArgumentException e)
+				{
+					throw new Asn1Exception("corrupted stream detected", e);
+				}
+			}
+		}
+
+		private void Set00Check(
+			bool enabled)
+		{
+			if (_in is IndefiniteLengthInputStream)
+			{
+				((IndefiniteLengthInputStream) _in).SetEofOn00(enabled);
+			}
+		}
+
+		internal Asn1EncodableVector ReadVector()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			IAsn1Convertible obj;
+			while ((obj = ReadObject()) != null)
+			{
+				v.Add(obj.ToAsn1Object());
+			}
+
+			return v;
+		}
+	}
+}
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
new file mode 100644
index 000000000..dfc1641a4
--- /dev/null
+++ b/Crypto/src/asn1/Asn1Exception.cs
@@ -0,0 +1,27 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class Asn1Exception
+		: IOException
+	{
+		public Asn1Exception()
+			: base()
+		{
+		}
+
+		public Asn1Exception(
+			string message)
+			: base(message)
+		{
+		}
+
+		public Asn1Exception(
+			string		message,
+			Exception	exception)
+			: base(message, exception)
+		{
+		}
+	}
+}
diff --git a/Crypto/src/asn1/Asn1InputStream.cs b/Crypto/src/asn1/Asn1InputStream.cs
new file mode 100644
index 000000000..9a9761653
--- /dev/null
+++ b/Crypto/src/asn1/Asn1InputStream.cs
@@ -0,0 +1,339 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Utilities;
+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);
+			}
+		}
+	}
+}
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
new file mode 100644
index 000000000..8827d8329
--- /dev/null
+++ b/Crypto/src/asn1/Asn1ParsingException.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class Asn1ParsingException
+		: InvalidOperationException
+	{
+		public Asn1ParsingException()
+			: base()
+		{
+		}
+
+		public Asn1ParsingException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public Asn1ParsingException(
+			string		message,
+			Exception	exception)
+			: base(message, exception)
+		{
+		}
+	}
+}
diff --git a/Crypto/src/asn1/Asn1Sequence.cs b/Crypto/src/asn1/Asn1Sequence.cs
new file mode 100644
index 000000000..3131ead84
--- /dev/null
+++ b/Crypto/src/asn1/Asn1Sequence.cs
@@ -0,0 +1,255 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public abstract class Asn1Sequence
+		: Asn1Object, IEnumerable
+    {
+        private readonly IList seq;
+
+		/**
+         * return an Asn1Sequence from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static Asn1Sequence GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Asn1Sequence)
+            {
+                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");
+		}
+
+		/**
+         * Return an ASN1 sequence from a tagged object. There is a special
+         * case here, if an object appears to have been explicitly tagged on
+         * reading but we were expecting it to be implicitly tagged in the
+         * normal course of events it indicates that we lost the surrounding
+         * sequence - so we need to add it back (this will happen if the tagged
+         * object is a sequence that contains other sequences). If you are
+         * dealing with implicitly tagged sequences you really <b>should</b>
+         * be using this method.
+         *
+         * @param obj the tagged object.
+         * @param explicitly true if the object is meant to be explicitly tagged,
+         *          false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *          be converted.
+         */
+        public static Asn1Sequence GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+			Asn1Object inner = obj.GetObject();
+
+			if (explicitly)
+            {
+                if (!obj.IsExplicit())
+                    throw new ArgumentException("object implicit - explicit expected.");
+
+				return (Asn1Sequence) inner;
+            }
+
+			//
+            // constructed object which appears to be explicitly tagged
+            // when it should be implicit means we have to add the
+            // surrounding sequence.
+            //
+            if (obj.IsExplicit())
+            {
+                if (obj is BerTaggedObject)
+                {
+                    return new BerSequence(inner);
+                }
+
+				return new DerSequence(inner);
+            }
+
+			if (inner is Asn1Sequence)
+            {
+                return (Asn1Sequence) inner;
+            }
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		protected internal Asn1Sequence(
+			int capacity)
+		{
+            seq = Platform.CreateArrayList(capacity);
+		}
+
+		public virtual IEnumerator GetEnumerator()
+		{
+			return seq.GetEnumerator();
+		}
+
+		[Obsolete("Use GetEnumerator() instead")]
+		public IEnumerator GetObjects()
+        {
+            return GetEnumerator();
+        }
+
+		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 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;
+			}
+
+			public Asn1Object ToAsn1Object()
+			{
+				return outer;
+			}
+		}
+
+		public virtual Asn1SequenceParser Parser
+		{
+			get { return new Asn1SequenceParserImpl(this); }
+		}
+
+        /**
+         * return the object at the sequence position indicated by index.
+         *
+         * @param index the sequence number (starting at zero) of the object
+         * @return the object at the sequence position indicated by index.
+         */
+		public virtual Asn1Encodable this[int index]
+		{
+			get { return (Asn1Encodable) seq[index]; }
+		}
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+        public Asn1Encodable GetObjectAt(
+            int index)
+        {
+             return this[index];
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+        {
+			get { return Count; }
+        }
+
+		public virtual int Count
+		{
+			get { return seq.Count; }
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+			int hc = Count;
+
+			foreach (object o in this)
+			{
+				hc *= 17;
+				if (o == null)
+				{
+					hc ^= DerNull.Instance.GetHashCode();
+				}
+				else
+                {
+					hc ^= o.GetHashCode();
+                }
+            }
+
+			return hc;
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			Asn1Sequence other = asn1Object as Asn1Sequence;
+
+			if (other == null)
+                return false;
+
+			if (Count != other.Count)
+                return false;
+
+			IEnumerator s1 = GetEnumerator();
+            IEnumerator s2 = other.GetEnumerator();
+
+			while (s1.MoveNext() && s2.MoveNext())
+			{
+				Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
+				Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
+
+				if (!o1.Equals(o2))
+					return false;
+			}
+
+			return true;
+        }
+
+		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;
+
+			return encObj;
+		}
+
+		protected internal void AddObject(
+            Asn1Encodable obj)
+        {
+            seq.Add(obj);
+        }
+
+		public override string ToString()
+		{
+			return CollectionUtilities.ToString(seq);
+		}
+    }
+}
diff --git a/Crypto/src/asn1/Asn1Set.cs b/Crypto/src/asn1/Asn1Set.cs
new file mode 100644
index 000000000..f5b66495c
--- /dev/null
+++ b/Crypto/src/asn1/Asn1Set.cs
@@ -0,0 +1,326 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1
+{
+    abstract public class Asn1Set
+        : Asn1Object, IEnumerable
+    {
+        private readonly IList _set;
+
+		/**
+         * return an ASN1Set from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static Asn1Set GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is Asn1Set)
+            {
+                return (Asn1Set)obj;
+            }
+
+			throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+        }
+
+        /**
+         * Return an ASN1 set from a tagged object. There is a special
+         * case here, if an object appears to have been explicitly tagged on
+         * reading but we were expecting it to be implicitly tagged in the
+         * normal course of events it indicates that we lost the surrounding
+         * set - so we need to add it back (this will happen if the tagged
+         * object is a sequence that contains other sequences). If you are
+         * dealing with implicitly tagged sets you really <b>should</b>
+         * be using this method.
+         *
+         * @param obj the tagged object.
+         * @param explicitly true if the object is meant to be explicitly tagged
+         *          false otherwise.
+         * @exception ArgumentException if the tagged object cannot
+         *          be converted.
+         */
+        public static Asn1Set GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+			Asn1Object inner = obj.GetObject();
+
+			if (explicitly)
+            {
+                if (!obj.IsExplicit())
+                    throw new ArgumentException("object implicit - explicit expected.");
+
+				return (Asn1Set) inner;
+            }
+
+			//
+            // constructed object which appears to be explicitly tagged
+            // and it's really implicit means we have to add the
+            // surrounding sequence.
+            //
+            if (obj.IsExplicit())
+            {
+                return new DerSet(inner);
+            }
+
+			if (inner is Asn1Set)
+            {
+                return (Asn1Set) inner;
+            }
+
+            //
+            // in this case the parser returns a sequence, convert it
+            // into a set.
+            //
+			if (inner is Asn1Sequence)
+            {
+				Asn1EncodableVector v = new Asn1EncodableVector();
+				Asn1Sequence s = (Asn1Sequence) inner;
+
+				foreach (Asn1Encodable ae in s)
+				{
+                    v.Add(ae);
+                }
+
+				// 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");
+		}
+
+		protected internal Asn1Set(
+			int capacity)
+        {
+			_set = Platform.CreateArrayList(capacity);
+        }
+
+		public virtual IEnumerator GetEnumerator()
+		{
+			return _set.GetEnumerator();
+		}
+
+		[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]; }
+		}
+
+		[Obsolete("Use 'object[index]' syntax instead")]
+		public Asn1Encodable GetObjectAt(
+            int index)
+        {
+             return this[index];
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+        {
+			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
+//				if (obj is Asn1OctetString)
+//					return ((Asn1OctetString)obj).Parser;
+
+				return obj;
+			}
+
+			public virtual Asn1Object ToAsn1Object()
+			{
+				return outer;
+			}
+		}
+
+		public Asn1SetParser Parser
+		{
+			get { return new Asn1SetParserImpl(this); }
+		}
+
+		protected override int Asn1GetHashCode()
+		{
+            int hc = Count;
+
+			foreach (object o in this)
+			{
+				hc *= 17;
+				if (o == null)
+				{
+					hc ^= DerNull.Instance.GetHashCode();
+				}
+				else
+                {
+					hc ^= o.GetHashCode();
+                }
+            }
+
+			return hc;
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			Asn1Set other = asn1Object as Asn1Set;
+
+			if (other == null)
+				return false;
+
+			if (Count != other.Count)
+            {
+                return false;
+            }
+
+			IEnumerator s1 = GetEnumerator();
+            IEnumerator s2 = other.GetEnumerator();
+
+			while (s1.MoveNext() && s2.MoveNext())
+			{
+				Asn1Object o1 = GetCurrent(s1).ToAsn1Object();
+				Asn1Object o2 = GetCurrent(s2).ToAsn1Object();
+
+				if (!o1.Equals(o2))
+					return false;
+			}
+
+			return true;
+        }
+
+		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;
+
+			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()
+        {
+			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)
+        {
+            _set.Add(obj);
+        }
+
+		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
new file mode 100644
index 000000000..644060765
--- /dev/null
+++ b/Crypto/src/asn1/BEROctetStringGenerator.cs
@@ -0,0 +1,121 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class BerOctetStringGenerator
+		: BerGenerator
+	{
+		public BerOctetStringGenerator(Stream outStream)
+			: base(outStream)
+		{
+			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.OctetString);
+		}
+
+		public BerOctetStringGenerator(
+			Stream	outStream,
+			int		tagNo,
+			bool	isExplicit)
+			: base(outStream, tagNo, isExplicit)
+		{
+			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.OctetString);
+		}
+
+		public Stream GetOctetOutputStream()
+		{
+			return GetOctetOutputStream(new byte[1000]); // limit for CER encoding.
+		}
+
+		public Stream GetOctetOutputStream(
+			int bufSize)
+		{
+			return bufSize < 1
+				?	GetOctetOutputStream()
+				:	GetOctetOutputStream(new byte[bufSize]);
+		}
+
+		public Stream GetOctetOutputStream(
+			byte[] buf)
+		{
+			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);
+            }
+        }
+	}
+}
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
new file mode 100644
index 000000000..cfea89f21
--- /dev/null
+++ b/Crypto/src/asn1/DefiniteLengthInputStream.cs
@@ -0,0 +1,90 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+    class DefiniteLengthInputStream
+        : LimitedInputStream
+    {
+		private static readonly byte[] EmptyBytes = new byte[0];
+
+		private readonly int _originalLength;
+		private int _remaining;
+
+        internal DefiniteLengthInputStream(
+            Stream	inStream,
+            int		length)
+            : base(inStream, length)
+        {
+			if (length < 0)
+				throw new ArgumentException("negative lengths not allowed", "length");
+
+			this._originalLength = length;
+			this._remaining = length;
+
+			if (length == 0)
+			{
+				SetParentEofDetect(true);
+			}
+        }
+
+		internal int Remaining
+		{
+			get { return _remaining; }
+		}
+
+		public override int ReadByte()
+        {
+			if (_remaining == 0)
+				return -1;
+
+			int b = _in.ReadByte();
+
+			if (b < 0)
+				throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
+
+			if (--_remaining == 0)
+			{
+				SetParentEofDetect(true);
+			}
+
+			return b;
+        }
+
+		public override int Read(
+			byte[]	buf,
+			int		off,
+			int		len)
+		{
+			if (_remaining == 0)
+				return 0;
+
+			int toRead = System.Math.Min(len, _remaining);
+			int numRead = _in.Read(buf, off, toRead);
+
+			if (numRead < 1)
+				throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
+
+			if ((_remaining -= numRead) == 0)
+			{
+				SetParentEofDetect(true);
+			}
+
+			return numRead;
+		}
+
+		internal byte[] ToArray()
+		{
+			if (_remaining == 0)
+				return EmptyBytes;
+
+			byte[] bytes = new byte[_remaining];
+			if ((_remaining -= Streams.ReadFully(_in, bytes)) != 0)
+				throw new EndOfStreamException("DEF length " + _originalLength + " object truncated by " + _remaining);
+			SetParentEofDetect(true);
+			return bytes;
+		}
+    }
+}
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
new file mode 100644
index 000000000..41ccae8a1
--- /dev/null
+++ b/Crypto/src/asn1/DerBoolean.cs
@@ -0,0 +1,110 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class DerBoolean
+        : Asn1Object
+    {
+        private readonly byte value;
+
+		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.
+         */
+        public static DerBoolean GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerBoolean)
+            {
+                return (DerBoolean) obj;
+            }
+
+			throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+		/**
+         * return a DerBoolean from the passed in bool.
+         */
+        public static DerBoolean GetInstance(
+            bool value)
+        {
+            return value ? True : False;
+        }
+
+		/**
+         * return a Boolean 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 DerBoolean GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerBoolean)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerBoolean(((Asn1OctetString)o).GetOctets());
+        }
+
+		public DerBoolean(
+            byte[] 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?
+            this.value = val[0];
+        }
+
+		private DerBoolean(
+            bool value)
+        {
+            this.value = value ? (byte)0xff : (byte)0;
+        }
+
+		public bool IsTrue
+		{
+			get { return value != 0; }
+		}
+
+		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 });
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			DerBoolean other = asn1Object as DerBoolean;
+
+			if (other == null)
+				return false;
+
+			return IsTrue == other.IsTrue;
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+			return IsTrue.GetHashCode();
+        }
+
+		public override string ToString()
+		{
+			return IsTrue ? "TRUE" : "FALSE";
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerEnumerated.cs b/Crypto/src/asn1/DerEnumerated.cs
new file mode 100644
index 000000000..0e67e6dbe
--- /dev/null
+++ b/Crypto/src/asn1/DerEnumerated.cs
@@ -0,0 +1,100 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    public class DerEnumerated
+        : Asn1Object
+    {
+        private readonly byte[] bytes;
+
+		/**
+         * return an integer from the passed in object
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerEnumerated GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is DerEnumerated)
+            {
+                return (DerEnumerated)obj;
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + obj.GetType().Name);
+        }
+
+        /**
+         * return an Enumerated 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 DerEnumerated GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			if (isExplicit || o is DerEnumerated)
+			{
+				return GetInstance(o);
+			}
+
+			return new DerEnumerated(((Asn1OctetString)o).GetOctets());
+        }
+
+        public DerEnumerated(
+            int val)
+        {
+            bytes = BigInteger.ValueOf(val).ToByteArray();
+        }
+
+        public DerEnumerated(
+            BigInteger val)
+        {
+            bytes = val.ToByteArray();
+        }
+
+        public DerEnumerated(
+            byte[]   bytes)
+        {
+            this.bytes = bytes;
+        }
+
+        public BigInteger Value
+        {
+            get
+            {
+                return new BigInteger(bytes);
+            }
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.Enumerated, bytes);
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			DerEnumerated other = asn1Object as DerEnumerated;
+
+			if (other == null)
+				return false;
+
+			return Arrays.AreEqual(this.bytes, other.bytes);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+			return Arrays.GetHashCode(bytes);
+        }
+    }
+}
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
new file mode 100644
index 000000000..0a0e6fd7c
--- /dev/null
+++ b/Crypto/src/asn1/DerGeneralizedTime.cs
@@ -0,0 +1,305 @@
+using System;
+using System.Globalization;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Generalized time object.
+     */
+    public class DerGeneralizedTime
+        : Asn1Object
+    {
+        private readonly string time;
+
+		/**
+         * return a generalized time from the passed in object
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static DerGeneralizedTime GetInstance(
+            object obj)
+        {
+			if (obj == null || obj is DerGeneralizedTime)
+            {
+                return (DerGeneralizedTime)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
+         * @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 DerGeneralizedTime GetInstance(
+            Asn1TaggedObject	obj,
+            bool				isExplicit)
+        {
+			Asn1Object o = obj.GetObject();
+
+			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;
+
+			try
+			{
+				ToDateTime();
+			}
+			catch (FormatException e)
+			{
+				throw new ArgumentException("invalid date string: " + e.Message);
+			}
+		}
+
+		/**
+         * base constructor from a local time object
+         */
+        public DerGeneralizedTime(
+            DateTime time)
+        {
+            this.time = time.ToString(@"yyyyMMddHHmmss\Z");
+        }
+
+		internal DerGeneralizedTime(
+            byte[] bytes)
+        {
+            //
+            // explicitly convert to characters
+            //
+            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 - always in the form of
+         *  YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+         * <p>
+         * Normally in a certificate we would expect "Z" rather than "GMT",
+         * however adding the "GMT" means we can just use:
+         * <pre>
+         *     dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+         * </pre>
+         * To read in the time and Get a date which is compatible with our local
+         * time zone.</p>
+         */
+        public string GetTime()
+        {
+            //
+            // standardise the format.
+            //
+            if (time[time.Length - 1] == 'Z')
+            {
+                return time.Substring(0, time.Length - 1) + "GMT+00:00";
+            }
+            else
+            {
+                int signPos = time.Length - 5;
+                char sign = time[signPos];
+                if (sign == '-' || sign == '+')
+                {
+                    return time.Substring(0, signPos)
+                        + "GMT"
+                        + time.Substring(signPos, 3)
+                        + ":"
+                        + time.Substring(signPos + 3);
+                }
+                else
+                {
+                    signPos = time.Length - 3;
+                    sign = time[signPos];
+                    if (sign == '-' || sign == '+')
+                    {
+                        return time.Substring(0, signPos)
+                            + "GMT"
+                            + time.Substring(signPos)
+                            + ":00";
+                    }
+                }
+            }
+
+            return time + CalculateGmtOffset();
+        }
+
+		private string CalculateGmtOffset()
+		{
+			char sign = '+';
+            DateTime time = ToDateTime();
+
+#if (SILVERLIGHT || PORTABLE)
+            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;
+#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;
+#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?
+//				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 Strings.ToAsciiByteArray(time);
+        }
+
+		internal override void Encode(
+            DerOutputStream derOut)
+        {
+            derOut.WriteEncoded(Asn1Tags.GeneralizedTime, GetOctets());
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+        {
+			DerGeneralizedTime other = asn1Object as DerGeneralizedTime;
+
+			if (other == null)
+				return false;
+
+			return this.time.Equals(other.time);
+        }
+
+		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
new file mode 100644
index 000000000..7dc963729
--- /dev/null
+++ b/Crypto/src/asn1/DerObjectIdentifier.cs
@@ -0,0 +1,242 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+using Org.BouncyCastle.Math;
+
+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;
+
+		/**
+         * return an Oid from the passed in object
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        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");
+        }
+
+		/**
+         * return an object Identifier 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 DerObjectIdentifier GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(obj.GetObject());
+        }
+
+		public DerObjectIdentifier(
+            string identifier)
+        {
+			if (identifier == null)
+				throw new ArgumentNullException("identifier");
+			if (!OidRegex.IsMatch(identifier))
+				throw new FormatException("string " + identifier + " not an OID");
+
+			this.identifier = identifier;
+        }
+
+		// TODO Change to ID?
+		public string Id
+        {
+            get { return identifier; }
+        }
+
+		public virtual DerObjectIdentifier Branch(string branchID)
+		{
+			return new DerObjectIdentifier(identifier + "." + branchID);
+		}
+
+        /**
+         * Return  true if this oid is an extension of the passed in branch, stem.
+         * @param stem the arc or branch that is a possible parent.
+         * @return  true if the branch is on the passed in stem, false otherwise.
+         */
+        public virtual bool On(DerObjectIdentifier stem)
+        {
+            string id = Id, stemId = stem.Id;
+            return id.Length > stemId.Length && id[stemId.Length] == '.' && id.StartsWith(stemId);
+        }
+
+        internal DerObjectIdentifier(
+            byte[] bytes)
+            : this(MakeOidStringFromBytes(bytes))
+        {
+        }
+
+		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);
+			}
+		}
+
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+            OidTokenizer tok = new OidTokenizer(identifier);
+            MemoryStream bOut = new MemoryStream();
+            DerOutputStream dOut = new DerOutputStream(bOut);
+
+			string token = tok.NextToken();
+            int first = int.Parse(token);
+
+			token = tok.NextToken();
+            int second = int.Parse(token);
+
+            WriteField(bOut, first * 40 + second);
+
+            while (tok.HasMoreTokens)
+            {
+				token = tok.NextToken();
+				if (token.Length < 18)
+				{
+					WriteField(bOut, Int64.Parse(token));
+				}
+				else
+				{
+					WriteField(bOut, new BigInteger(token));
+				}
+			}
+
+            dOut.Dispose();
+
+			derOut.WriteEncoded(Asn1Tags.ObjectIdentifier, bOut.ToArray());
+        }
+
+		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();
+		}
+	}
+}
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
new file mode 100644
index 000000000..dd67d2fed
--- /dev/null
+++ b/Crypto/src/asn1/DerSequence.cs
@@ -0,0 +1,85 @@
+using System.Collections;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	public class DerSequence
+		: Asn1Sequence
+	{
+		public static readonly DerSequence Empty = new DerSequence();
+
+		public static DerSequence FromVector(
+			Asn1EncodableVector v)
+		{
+			return v.Count < 1 ? Empty : new DerSequence(v);
+		}
+
+		/**
+		 * create an empty sequence
+		 */
+		public DerSequence()
+			: base(0)
+		{
+		}
+
+		/**
+		 * create a sequence containing one object
+		 */
+		public DerSequence(
+			Asn1Encodable obj)
+			: base(1)
+		{
+			AddObject(obj);
+		}
+
+		public DerSequence(
+			params Asn1Encodable[] v)
+			: base(v.Length)
+		{
+			foreach (Asn1Encodable ae in v)
+			{
+				AddObject(ae);
+			}
+		}
+
+		/**
+		 * create a sequence containing a vector of objects.
+		 */
+		public DerSequence(
+			Asn1EncodableVector v)
+			: base(v.Count)
+		{
+			foreach (Asn1Encodable ae in v)
+			{
+				AddObject(ae);
+			}
+		}
+
+		/*
+		 * A note on the implementation:
+		 * <p>
+		 * As Der requires the constructed, definite-length model to
+		 * be used for structured types, this varies slightly from the
+		 * ASN.1 descriptions given. Rather than just outputing Sequence,
+		 * we also have to specify Constructed, and the objects length.
+		 */
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			// TODO Intermediate buffer could be avoided if we could calculate expected length
+			MemoryStream bOut = new MemoryStream();
+			DerOutputStream dOut = new DerOutputStream(bOut);
+
+			foreach (Asn1Encodable obj in this)
+			{
+				dOut.WriteObject(obj);
+			}
+
+			dOut.Dispose();
+
+			byte[] bytes = bOut.ToArray();
+
+			derOut.WriteEncoded(Asn1Tags.Sequence | Asn1Tags.Constructed, bytes);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/DerSet.cs b/Crypto/src/asn1/DerSet.cs
new file mode 100644
index 000000000..6d3f438bd
--- /dev/null
+++ b/Crypto/src/asn1/DerSet.cs
@@ -0,0 +1,108 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	/**
+	 * A Der encoded set object
+	 */
+	public class DerSet
+		: Asn1Set
+	{
+		public static readonly DerSet Empty = new DerSet();
+
+		public static DerSet FromVector(
+			Asn1EncodableVector v)
+		{
+			return v.Count < 1 ? Empty : new DerSet(v);
+		}
+
+		internal static DerSet FromVector(
+			Asn1EncodableVector	v,
+			bool				needsSorting)
+		{
+			return v.Count < 1 ? Empty : new DerSet(v, needsSorting);
+		}
+
+		/**
+		 * create an empty set
+		 */
+		public DerSet()
+			: base(0)
+		{
+		}
+
+		/**
+		 * @param obj - a single object that makes up the set.
+		 */
+		public DerSet(
+			Asn1Encodable obj)
+			: base(1)
+		{
+			AddObject(obj);
+		}
+
+		public DerSet(
+			params Asn1Encodable[] v)
+			: base(v.Length)
+		{
+			foreach (Asn1Encodable o in v)
+			{
+				AddObject(o);
+			}
+
+			Sort();
+		}
+
+		/**
+		 * @param v - a vector of objects making up the set.
+		 */
+		public DerSet(
+			Asn1EncodableVector v)
+			: this(v, true)
+		{
+		}
+
+		internal DerSet(
+			Asn1EncodableVector	v,
+			bool				needsSorting)
+			: base(v.Count)
+		{
+			foreach (Asn1Encodable o in v)
+			{
+				AddObject(o);
+			}
+
+			if (needsSorting)
+			{
+				Sort();
+			}
+		}
+
+		/*
+		 * A note on the implementation:
+		 * <p>
+		 * As Der requires the constructed, definite-length model to
+		 * be used for structured types, this varies slightly from the
+		 * ASN.1 descriptions given. Rather than just outputing Set,
+		 * we also have to specify Constructed, and the objects length.
+		 */
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			// TODO Intermediate buffer could be avoided if we could calculate expected length
+			MemoryStream bOut = new MemoryStream();
+			DerOutputStream dOut = new DerOutputStream(bOut);
+
+			foreach (Asn1Encodable obj in this)
+			{
+				dOut.WriteObject(obj);
+			}
+
+            dOut.Dispose();
+
+			byte[] bytes = bOut.ToArray();
+
+			derOut.WriteEncoded(Asn1Tags.Set | Asn1Tags.Constructed, bytes);
+		}
+	}
+}
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/DerUnknownTag.cs b/Crypto/src/asn1/DerUnknownTag.cs
new file mode 100644
index 000000000..1e0e61495
--- /dev/null
+++ b/Crypto/src/asn1/DerUnknownTag.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * We insert one of these when we find a tag we don't recognise.
+     */
+    public class DerUnknownTag
+        : Asn1Object
+    {
+		private readonly bool	isConstructed;
+        private readonly int	tag;
+        private readonly byte[]	data;
+
+        /**
+         * @param tag the tag value.
+         * @param data the contents octets.
+         */
+        public DerUnknownTag(
+            int		tag,
+            byte[]	data)
+			: this(false, tag, data)
+        {
+        }
+
+		public DerUnknownTag(
+			bool	isConstructed,
+			int		tag,
+			byte[]	data)
+		{
+			if (data == null)
+				throw new ArgumentNullException("data");
+
+			this.isConstructed = isConstructed;
+			this.tag = tag;
+			this.data = data;
+		}
+
+		public bool IsConstructed
+		{
+			get { return isConstructed; }
+		}
+
+		public int Tag
+        {
+			get { return tag; }
+        }
+
+		public byte[] GetData()
+        {
+            return data;
+        }
+
+        internal override void Encode(
+            DerOutputStream derOut)
+        {
+			derOut.WriteEncoded(isConstructed ? Asn1Tags.Constructed : 0, tag, data);
+        }
+
+		protected override bool Asn1Equals(
+			Asn1Object asn1Object)
+		{
+			DerUnknownTag other = asn1Object as DerUnknownTag;
+
+			if (other == null)
+				return false;
+
+			return this.isConstructed == other.isConstructed
+				&& this.tag == other.tag
+				&& Arrays.AreEqual(this.data, other.data);
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+			return isConstructed.GetHashCode() ^ tag.GetHashCode() ^ Arrays.GetHashCode(data);
+        }
+    }
+}
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
new file mode 100644
index 000000000..56c1bdfbc
--- /dev/null
+++ b/Crypto/src/asn1/IndefiniteLengthInputStream.cs
@@ -0,0 +1,166 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1
+{
+	class IndefiniteLengthInputStream
+		: LimitedInputStream
+	{
+        private int _lookAhead;
+        private bool _eofOn00 = true;
+
+		internal IndefiniteLengthInputStream(
+			Stream	inStream,
+			int		limit)
+			: base(inStream, limit)
+		{
+            _lookAhead = RequireByte();
+            CheckForEof();
+		}
+
+		internal void SetEofOn00(
+			bool eofOn00)
+		{
+			_eofOn00 = eofOn00;
+            CheckForEof();
+        }
+
+		private bool CheckForEof()
+		{
+            if (_lookAhead == 0x00 && _eofOn00)
+            {
+                int extra = RequireByte();
+                if (extra != 0)
+                {
+                    throw new IOException("malformed end-of-contents marker");
+                }
+
+                _lookAhead = -1;
+                SetParentEofDetect(true);
+            }
+            return _lookAhead < 0;
+        }
+
+		public override int Read(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+		{
+			// Only use this optimisation if we aren't checking for 00
+			if (_eofOn00 || count <= 1)
+				return base.Read(buffer, offset, count);
+
+			if (_lookAhead < 0)
+				return 0;
+
+			int numRead = _in.Read(buffer, offset + 1, count - 1);
+
+			if (numRead <= 0)
+			{
+				// Corrupted stream
+				throw new EndOfStreamException();
+			}
+
+			buffer[offset] = (byte)_lookAhead;
+			_lookAhead = RequireByte();
+
+			return numRead + 1;
+		}
+
+		public override int ReadByte()
+		{
+			if (CheckForEof())
+				return -1;
+
+            int result = _lookAhead;
+            _lookAhead = RequireByte();
+            return result;
+		}
+
+        private int RequireByte()
+        {
+            int b = _in.ReadByte();
+            if (b < 0)
+            {
+                // Corrupted stream
+                throw new EndOfStreamException();
+            }
+            return b;
+        }
+	}
+}
+
+//using System;
+//using System.IO;
+
+//namespace Org.BouncyCastle.Asn1
+//{
+//    class IndefiniteLengthInputStream
+//        : LimitedInputStream
+//    {
+//        private bool _eofReached = false;
+//        private bool _eofOn00 = true;
+
+//        internal IndefiniteLengthInputStream(
+//            Stream	inStream,
+//            int		limit)
+//            : base(inStream, limit)
+//        {
+//        }
+
+//        internal void SetEofOn00(
+//            bool eofOn00)
+//        {
+//            _eofOn00 = eofOn00;
+//        }
+
+//        public override int Read(
+//            byte[]	buffer,
+//            int		offset,
+//            int		count)
+//        {
+//            if (_eofReached)
+//                return 0;
+
+//            if (_eofOn00)
+//                return base.Read(buffer, offset, count);
+
+//            int numRead = _in.Read(buffer, offset, count);
+
+//            if (numRead <= 0)
+//                throw new EndOfStreamException();
+
+//            return numRead;
+//        }
+
+//        public override int ReadByte()
+//        {
+//            if (_eofReached)
+//                return -1;
+
+//            int b1 = _in.ReadByte();
+
+//            if (b1 < 0)
+//                throw new EndOfStreamException();
+
+//            if (b1 == 0 && _eofOn00)
+//            {
+//                int b2 = _in.ReadByte();
+
+//                if (b2 < 0)
+//                    throw new EndOfStreamException();
+
+//                if (b2 == 0)
+//                {
+//                    _eofReached = true;
+//                    SetParentEofDetect(true);
+//                    return -1;
+//                }
+
+//                throw new InvalidDataException();
+//            }
+
+//            return b1;
+//        }
+//    }
+//}
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
new file mode 100644
index 000000000..5e3dd076e
--- /dev/null
+++ b/Crypto/src/asn1/LazyDERSequence.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Asn1
+{
+	internal class LazyDerSequence
+		: DerSequence
+	{
+		private byte[]	encoded;
+		private bool	parsed = false;
+
+		internal LazyDerSequence(
+			byte[] encoded)
+		{
+			this.encoded = encoded;
+		}
+
+		private void Parse()
+		{
+			lock (this)
+			{
+				if (!parsed)
+				{
+					Asn1InputStream e = new LazyAsn1InputStream(encoded);
+
+					Asn1Object o;
+					while ((o = e.ReadObject()) != null)
+					{
+						AddObject(o);
+					}
+
+					encoded = null;
+					parsed = true;
+				}
+			}
+		}
+
+		public override Asn1Encodable this[int index]
+		{
+			get
+			{
+				Parse();
+
+				return base[index];
+			}
+		}
+
+		public override IEnumerator GetEnumerator()
+		{
+			Parse();
+
+			return base.GetEnumerator();
+		}
+
+		public override int Count
+		{
+			get
+			{
+				Parse();
+
+				return base.Count;
+			}
+		}
+
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			lock (this)
+			{
+				if (parsed)
+				{
+					base.Encode(derOut);
+				}
+				else
+				{
+					derOut.WriteEncoded(Asn1Tags.Sequence | Asn1Tags.Constructed, encoded);
+				}
+			}
+		}
+	}
+}
diff --git a/Crypto/src/asn1/LazyDERSet.cs b/Crypto/src/asn1/LazyDERSet.cs
new file mode 100644
index 000000000..84fce4808
--- /dev/null
+++ b/Crypto/src/asn1/LazyDERSet.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+
+namespace Org.BouncyCastle.Asn1
+{
+	internal class LazyDerSet
+		: DerSet
+	{
+		private byte[]	encoded;
+		private bool	parsed = false;
+
+		internal LazyDerSet(
+			byte[] encoded)
+		{
+			this.encoded = encoded;
+		}
+
+		private void Parse()
+		{
+			lock (this)
+			{
+				if (!parsed)
+				{
+					Asn1InputStream e = new LazyAsn1InputStream(encoded);
+
+					Asn1Object o;
+					while ((o = e.ReadObject()) != null)
+					{
+						AddObject(o);
+					}
+
+					encoded = null;
+					parsed = true;
+				}
+			}
+		}
+
+		public override Asn1Encodable this[int index]
+		{
+			get
+			{
+				Parse();
+
+				return base[index];
+			}
+		}
+
+		public override IEnumerator GetEnumerator()
+		{
+			Parse();
+
+			return base.GetEnumerator();
+		}
+
+		public override int Count
+		{
+			get
+			{
+				Parse();
+
+				return base.Count;
+			}
+		}
+
+		internal override void Encode(
+			DerOutputStream derOut)
+		{
+			lock (this)
+			{
+				if (parsed)
+				{
+					base.Encode(derOut);
+				}
+				else
+				{
+					derOut.WriteEncoded(Asn1Tags.Set | Asn1Tags.Constructed, encoded);
+				}
+			}
+		}
+	}
+}
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
new file mode 100644
index 000000000..3c0164ce8
--- /dev/null
+++ b/Crypto/src/asn1/cms/AttributeTable.cs
@@ -0,0 +1,231 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class AttributeTable
+    {
+        private readonly IDictionary attributes;
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public AttributeTable(
+            Hashtable attrs)
+        {
+            this.attributes = Platform.CreateHashtable(attrs);
+        }
+#endif
+
+        public AttributeTable(
+            IDictionary attrs)
+        {
+            this.attributes = Platform.CreateHashtable(attrs);
+        }
+
+        public AttributeTable(
+            Asn1EncodableVector v)
+        {
+            this.attributes = Platform.CreateHashtable(v.Count);
+
+			foreach (Asn1Encodable o in v)
+            {
+                Attribute a = Attribute.GetInstance(o);
+
+				AddAttribute(a);
+            }
+        }
+
+        public AttributeTable(
+            Asn1Set s)
+        {
+            this.attributes = Platform.CreateHashtable(s.Count);
+
+			for (int i = 0; i != s.Count; i++)
+            {
+                Attribute a = Attribute.GetInstance(s[i]);
+
+                AddAttribute(a);
+            }
+        }
+
+		public AttributeTable(
+			Attributes attrs)
+			: this(Asn1Set.GetInstance(attrs.ToAsn1Object()))
+		{
+		}
+
+		private void AddAttribute(
+            Attribute a)
+        {
+			DerObjectIdentifier oid = a.AttrType;
+            object obj = attributes[oid];
+
+            if (obj == null)
+            {
+                attributes[oid] = a;
+            }
+            else
+            {
+                IList v;
+
+                if (obj is Attribute)
+                {
+                    v = Platform.CreateArrayList();
+
+                    v.Add(obj);
+                    v.Add(a);
+                }
+                else
+                {
+                    v = (IList) obj;
+
+                    v.Add(a);
+                }
+
+                attributes[oid] = v;
+            }
+        }
+
+		/// <summary>Return the first attribute matching the given OBJECT IDENTIFIER</summary>
+		public Attribute this[DerObjectIdentifier oid]
+		{
+			get
+			{
+				object obj = attributes[oid];
+
+				if (obj is IList)
+				{
+					return (Attribute)((IList)obj)[0];
+				}
+
+				return (Attribute) obj;
+			}
+		}
+
+		[Obsolete("Use 'object[oid]' syntax instead")]
+        public Attribute Get(
+            DerObjectIdentifier oid)
+        {
+			return this[oid];
+        }
+
+		/**
+        * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be
+        * empty if there are no attributes of the required type present.
+        *
+        * @param oid type of attribute required.
+        * @return a vector of all the attributes found of type oid.
+        */
+        public Asn1EncodableVector GetAll(
+            DerObjectIdentifier oid)
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            object obj = attributes[oid];
+
+			if (obj is IList)
+            {
+                foreach (Attribute a in (IList)obj)
+                {
+                    v.Add(a);
+                }
+            }
+            else if (obj != null)
+            {
+                v.Add((Attribute) obj);
+            }
+
+			return v;
+        }
+
+		public int Count
+		{
+			get
+			{
+				int total = 0;
+
+				foreach (object o in attributes.Values)
+				{
+					if (o is IList)
+					{
+						total += ((IList)o).Count;
+					}
+					else
+					{
+						++total;
+					}
+				}
+
+				return total;
+			}
+		}
+
+        public IDictionary ToDictionary()
+        {
+            return Platform.CreateHashtable(attributes);
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete("Use 'ToDictionary' instead")]
+		public Hashtable ToHashtable()
+        {
+            return new Hashtable(attributes);
+        }
+#endif
+
+        public Asn1EncodableVector ToAsn1EncodableVector()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			foreach (object obj in attributes.Values)
+            {
+                if (obj is IList)
+                {
+                    foreach (object el in (IList)obj)
+                    {
+                        v.Add(Attribute.GetInstance(el));
+                    }
+                }
+                else
+                {
+                    v.Add(Attribute.GetInstance(obj));
+                }
+            }
+
+			return v;
+        }
+
+		public Attributes ToAttributes()
+		{
+			return new Attributes(this.ToAsn1EncodableVector());
+		}
+
+		/**
+		 * Return a new table with the passed in attribute added.
+		 *
+		 * @param attrType
+		 * @param attrValue
+		 * @return
+		 */
+		public AttributeTable Add(DerObjectIdentifier attrType, Asn1Encodable attrValue)
+		{
+			AttributeTable newTable = new AttributeTable(attributes);
+
+			newTable.AddAttribute(new Attribute(attrType, new DerSet(attrValue)));
+
+			return newTable;
+		}
+
+		public AttributeTable Remove(DerObjectIdentifier attrType)
+		{
+			AttributeTable newTable = new AttributeTable(attributes);
+
+			newTable.attributes.Remove(attrType);
+
+			return newTable;
+		}
+    }
+}
diff --git a/Crypto/src/asn1/cms/Attributes.cs b/Crypto/src/asn1/cms/Attributes.cs
new file mode 100644
index 000000000..47cb66bdb
--- /dev/null
+++ b/Crypto/src/asn1/cms/Attributes.cs
@@ -0,0 +1,43 @@
+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;
+		}
+	}
+}
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
new file mode 100644
index 000000000..59009bda7
--- /dev/null
+++ b/Crypto/src/asn1/cms/CMSObjectIdentifiers.cs
@@ -0,0 +1,18 @@
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public abstract class CmsObjectIdentifiers
+    {
+        public static readonly DerObjectIdentifier Data = PkcsObjectIdentifiers.Data;
+        public static readonly DerObjectIdentifier SignedData = PkcsObjectIdentifiers.SignedData;
+        public static readonly DerObjectIdentifier EnvelopedData = PkcsObjectIdentifiers.EnvelopedData;
+        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 CompressedData = PkcsObjectIdentifiers.IdCTCompressedData;
+		public static readonly DerObjectIdentifier AuthEnvelopedData = PkcsObjectIdentifiers.IdCTAuthEnvelopedData;
+		public static readonly DerObjectIdentifier timestampedData = PkcsObjectIdentifiers.IdCTTimestampedData;
+    }
+}
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
new file mode 100644
index 000000000..61a277535
--- /dev/null
+++ b/Crypto/src/asn1/cms/ContentInfo.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections;
+
+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);
+		}
+	}
+}
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
new file mode 100644
index 000000000..47cd4a9f5
--- /dev/null
+++ b/Crypto/src/asn1/cms/EnvelopedData.cs
@@ -0,0 +1,167 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class EnvelopedData
+        : Asn1Encodable
+    {
+        private DerInteger				version;
+        private OriginatorInfo			originatorInfo;
+        private Asn1Set					recipientInfos;
+        private EncryptedContentInfo	encryptedContentInfo;
+        private Asn1Set					unprotectedAttrs;
+
+		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.recipientInfos = recipientInfos;
+            this.encryptedContentInfo = encryptedContentInfo;
+            this.unprotectedAttrs = unprotectedAttrs;
+        }
+
+		public EnvelopedData(
+            Asn1Sequence seq)
+        {
+            int index = 0;
+
+			version = (DerInteger) seq[index++];
+
+			object tmp = seq[index++];
+
+			if (tmp is Asn1TaggedObject)
+            {
+                originatorInfo = OriginatorInfo.GetInstance((Asn1TaggedObject) tmp, false);
+                tmp = seq[index++];
+            }
+
+			recipientInfos = Asn1Set.GetInstance(tmp);
+            encryptedContentInfo = EncryptedContentInfo.GetInstance(seq[index++]);
+
+			if (seq.Count > index)
+            {
+				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.
+         * @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 EnvelopedData GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		/**
+         * return an EnvelopedData object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static EnvelopedData GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is EnvelopedData)
+            {
+                return (EnvelopedData)obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new EnvelopedData((Asn1Sequence)obj);
+            }
+
+			throw new ArgumentException("Invalid EnvelopedData: " + obj.GetType().Name);
+        }
+
+		public DerInteger Version
+		{
+			get { return version; }
+		}
+
+		public OriginatorInfo OriginatorInfo
+		{
+			get { return originatorInfo; }
+		}
+
+		public Asn1Set RecipientInfos
+		{
+			get { return recipientInfos; }
+		}
+
+		public EncryptedContentInfo EncryptedContentInfo
+		{
+			get { return encryptedContentInfo; }
+		}
+
+		public Asn1Set UnprotectedAttrs
+		{
+			get { return unprotectedAttrs; }
+		}
+
+		/**
+         * 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 override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(version);
+
+			if (originatorInfo != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, originatorInfo));
+            }
+
+			v.Add(recipientInfos, encryptedContentInfo);
+
+			if (unprotectedAttrs != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, unprotectedAttrs));
+            }
+
+			return new BerSequence(v);
+        }
+    }
+}
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
new file mode 100644
index 000000000..ac1af961f
--- /dev/null
+++ b/Crypto/src/asn1/cms/IssuerAndSerialNumber.cs
@@ -0,0 +1,66 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class IssuerAndSerialNumber
+        : Asn1Encodable
+    {
+        private X509Name	name;
+        private DerInteger	serialNumber;
+
+        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);
+        }
+
+        public IssuerAndSerialNumber(
+            Asn1Sequence seq)
+        {
+            this.name = X509Name.GetInstance(seq[0]);
+            this.serialNumber = (DerInteger) seq[1];
+        }
+
+		public IssuerAndSerialNumber(
+            X509Name	name,
+            BigInteger	serialNumber)
+        {
+            this.name = name;
+            this.serialNumber = new DerInteger(serialNumber);
+        }
+
+        public IssuerAndSerialNumber(
+            X509Name	name,
+            DerInteger	serialNumber)
+        {
+            this.name = name;
+            this.serialNumber = serialNumber;
+        }
+
+		public X509Name Name
+		{
+			get { return name; }
+		}
+
+		public DerInteger SerialNumber
+		{
+			get { return serialNumber; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			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
new file mode 100644
index 000000000..8b06b1946
--- /dev/null
+++ b/Crypto/src/asn1/cms/OtherRecipientInfo.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class OtherRecipientInfo
+        : Asn1Encodable
+    {
+        private DerObjectIdentifier	oriType;
+        private Asn1Encodable		oriValue;
+
+		public OtherRecipientInfo(
+            DerObjectIdentifier	oriType,
+            Asn1Encodable		oriValue)
+        {
+            this.oriType = oriType;
+            this.oriValue = oriValue;
+        }
+
+		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.
+         * @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 OtherRecipientInfo GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		/**
+         * return a OtherRecipientInfo object from the given object.
+         *
+         * @param obj the object we want converted.
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        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);
+        }
+
+		public DerObjectIdentifier OriType
+		{
+			get { return oriType; }
+		}
+
+		public Asn1Encodable OriValue
+		{
+			get { return oriValue; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * OtherRecipientInfo ::= Sequence {
+         *    oriType OBJECT IDENTIFIER,
+         *    oriValue ANY DEFINED BY oriType }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(oriType, oriValue);
+        }
+    }
+}
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/SignedData.cs b/Crypto/src/asn1/cms/SignedData.cs
new file mode 100644
index 000000000..40ed09f32
--- /dev/null
+++ b/Crypto/src/asn1/cms/SignedData.cs
@@ -0,0 +1,282 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    /**
+     * a signed data object.
+     */
+    public class SignedData
+        : Asn1Encodable
+    {
+        private readonly DerInteger		version;
+        private readonly Asn1Set		digestAlgorithms;
+        private readonly ContentInfo	contentInfo;
+        private readonly Asn1Set		certificates;
+        private readonly Asn1Set		crls;
+        private readonly Asn1Set		signerInfos;
+        private readonly bool			certsBer;
+        private readonly bool		    crlsBer;
+
+		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");
+		}
+
+		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(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            version = (DerInteger)e.Current;
+
+			e.MoveNext();
+            digestAlgorithms = ((Asn1Set)e.Current);
+
+			e.MoveNext();
+            contentInfo = ContentInfo.GetInstance(e.Current);
+
+			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.
+                //
+                if (o is Asn1TaggedObject)
+                {
+                    Asn1TaggedObject tagged = (Asn1TaggedObject)o;
+
+                    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);
+                    }
+                }
+                else
+                {
+                    signerInfos = (Asn1Set) o;
+                }
+            }
+        }
+
+		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 {
+         *     version CMSVersion,
+         *     digestAlgorithms DigestAlgorithmIdentifiers,
+         *     encapContentInfo EncapsulatedContentInfo,
+         *     certificates [0] IMPLICIT CertificateSet OPTIONAL,
+         *     crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+         *     signerInfos SignerInfos
+         *   }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, digestAlgorithms, contentInfo);
+
+			if (certificates != null)
+            {
+                if (certsBer)
+                {
+                    v.Add(new BerTaggedObject(false, 0, certificates));
+                }
+                else
+                {
+                    v.Add(new DerTaggedObject(false, 0, certificates));
+                }
+            }
+
+			if (crls != null)
+            {
+                if (crlsBer)
+                {
+                    v.Add(new BerTaggedObject(false, 1, crls));
+                }
+                else
+                {
+                    v.Add(new DerTaggedObject(false, 1, crls));
+                }
+            }
+
+			v.Add(signerInfos);
+
+			return new BerSequence(v);
+        }
+    }
+}
diff --git a/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
new file mode 100644
index 000000000..ef71ddfc4
--- /dev/null
+++ b/Crypto/src/asn1/cms/SignerInfo.cs
@@ -0,0 +1,175 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+    public class SignerInfo
+        : Asn1Encodable
+    {
+        private DerInteger              version;
+        private SignerIdentifier        sid;
+        private AlgorithmIdentifier     digAlgorithm;
+        private Asn1Set                 authenticatedAttributes;
+        private AlgorithmIdentifier     digEncryptionAlgorithm;
+        private Asn1OctetString         encryptedDigest;
+        private Asn1Set                 unauthenticatedAttributes;
+
+        public static SignerInfo GetInstance(
+            object obj)
+        {
+            if (obj == null || 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(
+            SignerIdentifier        sid,
+            AlgorithmIdentifier     digAlgorithm,
+            Asn1Set                 authenticatedAttributes,
+            AlgorithmIdentifier     digEncryptionAlgorithm,
+            Asn1OctetString         encryptedDigest,
+            Asn1Set                 unauthenticatedAttributes)
+        {
+            if (sid.IsTagged)
+            {
+                this.version = new DerInteger(3);
+            }
+            else
+            {
+                this.version = new DerInteger(1);
+            }
+
+			this.sid = sid;
+            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();
+            sid = SignerIdentifier.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 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 {
+         *      version Version,
+         *      SignerIdentifier sid,
+         *      digestAlgorithm DigestAlgorithmIdentifier,
+         *      authenticatedAttributes [0] IMPLICIT Attributes OPTIONAL,
+         *      digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier,
+         *      encryptedDigest EncryptedDigest,
+         *      unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL
+         *  }
+         *
+         *  EncryptedDigest ::= OCTET STRING
+         *
+         *  DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+         *
+         *  DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, sid, 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/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
new file mode 100644
index 000000000..c0037999a
--- /dev/null
+++ b/Crypto/src/asn1/crmf/OptionalValidity.cs
@@ -0,0 +1,64 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Crmf
+{
+    public class OptionalValidity
+        : Asn1Encodable
+    {
+        private readonly Time notBefore;
+        private readonly Time notAfter;
+
+        private OptionalValidity(Asn1Sequence seq)
+        {
+            foreach (Asn1TaggedObject tObj in seq)
+            {
+                if (tObj.TagNo == 0)
+                {
+                    notBefore = Time.GetInstance(tObj, true);
+                }
+                else
+                {
+                    notAfter = Time.GetInstance(tObj, true);
+                }
+            }
+        }
+
+        public static OptionalValidity GetInstance(object obj)
+        {
+            if (obj is OptionalValidity)
+                return (OptionalValidity)obj;
+
+            if (obj is Asn1Sequence)
+                return new OptionalValidity((Asn1Sequence)obj);
+
+            throw new ArgumentException("Invalid object: " + obj.GetType().Name, "obj");
+        }
+
+        /**
+         * <pre>
+         * OptionalValidity ::= SEQUENCE {
+         *                        notBefore  [0] Time OPTIONAL,
+         *                        notAfter   [1] Time OPTIONAL } --at least one MUST be present
+         * </pre>
+         * @return a basic ASN.1 object representation.
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+            if (notBefore != null)
+            {
+                v.Add(new DerTaggedObject(true, 0, notBefore));
+            }
+
+            if (notAfter != null)
+            {
+                v.Add(new DerTaggedObject(true, 1, notAfter));
+            }
+
+            return new DerSequence(v);
+        }
+    }
+}
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
new file mode 100644
index 000000000..6e0e023b9
--- /dev/null
+++ b/Crypto/src/asn1/cryptopro/CryptoProObjectIdentifiers.cs
@@ -0,0 +1,48 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    public abstract class CryptoProObjectIdentifiers
+    {
+        // GOST Algorithms OBJECT IDENTIFIERS :
+        // { iso(1) member-body(2) ru(643) rans(2) cryptopro(2)}
+        public const string GostID = "1.2.643.2.2";
+
+		public static readonly DerObjectIdentifier GostR3411 = new DerObjectIdentifier(GostID + ".9");
+
+		public static readonly DerObjectIdentifier GostR28147Cbc = new DerObjectIdentifier(GostID + ".21");
+
+		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");
+
+		// { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) hashes(30) }
+        public static readonly DerObjectIdentifier GostR3411x94CryptoProParamSet = new DerObjectIdentifier(GostID + ".30.1");
+
+		// { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) signs(32) }
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProA = new DerObjectIdentifier(GostID + ".32.2");
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProB = new DerObjectIdentifier(GostID + ".32.3");
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProC = new DerObjectIdentifier(GostID + ".32.4");
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProD = new DerObjectIdentifier(GostID + ".32.5");
+
+		// { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) exchanges(33) }
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProXchA = new DerObjectIdentifier(GostID + ".33.1");
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProXchB = new DerObjectIdentifier(GostID + ".33.2");
+        public static readonly DerObjectIdentifier GostR3410x94CryptoProXchC = new DerObjectIdentifier(GostID + ".33.3");
+
+		//{ iso(1) member-body(2)ru(643) rans(2) cryptopro(2) ecc-signs(35) }
+        public static readonly DerObjectIdentifier GostR3410x2001CryptoProA = new DerObjectIdentifier(GostID + ".35.1");
+        public static readonly DerObjectIdentifier GostR3410x2001CryptoProB = new DerObjectIdentifier(GostID + ".35.2");
+        public static readonly DerObjectIdentifier GostR3410x2001CryptoProC = new DerObjectIdentifier(GostID + ".35.3");
+
+		// { iso(1) member-body(2) ru(643) rans(2) cryptopro(2) ecc-exchanges(36) }
+        public static readonly DerObjectIdentifier GostR3410x2001CryptoProXchA  = new DerObjectIdentifier(GostID + ".36.0");
+        public static readonly DerObjectIdentifier GostR3410x2001CryptoProXchB  = new DerObjectIdentifier(GostID + ".36.1");
+
+		public static readonly DerObjectIdentifier GostElSgDH3410Default = new DerObjectIdentifier(GostID + ".36.0");
+        public static readonly DerObjectIdentifier GostElSgDH3410x1 = new DerObjectIdentifier(GostID + ".36.1");
+    }
+}
diff --git a/Crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs b/Crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
new file mode 100644
index 000000000..998e0e06f
--- /dev/null
+++ b/Crypto/src/asn1/cryptopro/ECGOST3410NamedCurves.cs
@@ -0,0 +1,179 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.CryptoPro
+{
+    /**
+    * table of the available named parameters for GOST 3410-2001.
+    */
+    public sealed class ECGost3410NamedCurves
+    {
+		private ECGost3410NamedCurves()
+		{
+		}
+
+        internal static readonly IDictionary objIds = Platform.CreateHashtable();
+        internal static readonly IDictionary parameters = Platform.CreateHashtable();
+        internal static readonly IDictionary names = Platform.CreateHashtable();
+
+        static ECGost3410NamedCurves()
+        {
+            BigInteger mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319");
+            BigInteger mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323");
+
+            FpCurve curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a
+                new BigInteger("166")); // b
+
+            ECDomainParameters ecParams = new ECDomainParameters(
+                curve,
+				curve.CreatePoint(
+					BigInteger.One, // x
+					new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612"), // y
+					false),
+                mod_q);
+
+			parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = ecParams;
+
+            mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319");
+            mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323");
+
+            curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"),
+                new BigInteger("166"));
+
+            ecParams = new ECDomainParameters(
+                curve,
+				curve.CreatePoint(
+					BigInteger.One, // x
+					new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612"), // y
+					false),
+                mod_q);
+
+            parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA] = ecParams;
+
+            mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823193"); //p
+            mod_q = new BigInteger("57896044618658097711785492504343953927102133160255826820068844496087732066703"); //q
+
+            curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a
+                new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595")); // b
+
+            ecParams = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+					BigInteger.One, // x
+					new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124"), // y
+					false),
+                mod_q); // q
+
+            parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProB] = ecParams;
+
+            mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619");
+            mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601");
+
+            curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"),
+                new BigInteger("32858"));
+
+            ecParams = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+					BigInteger.Zero, // x
+					new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247"), // y
+					false),
+                mod_q);
+
+            parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB] = ecParams;
+
+            mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); //p
+            mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); //q
+            curve = new FpCurve(
+                mod_p, // p
+                new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a
+                new BigInteger("32858")); // b
+
+            ecParams = new ECDomainParameters(
+                curve,
+                curve.CreatePoint(
+					BigInteger.Zero, // x
+					new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247"), // y
+					false),
+                mod_q); // q
+
+			parameters[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = ecParams;
+
+            objIds["GostR3410-2001-CryptoPro-A"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProA;
+            objIds["GostR3410-2001-CryptoPro-B"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProB;
+            objIds["GostR3410-2001-CryptoPro-C"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProC;
+            objIds["GostR3410-2001-CryptoPro-XchA"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA;
+            objIds["GostR3410-2001-CryptoPro-XchB"] = CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB;
+
+            names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProA] = "GostR3410-2001-CryptoPro-A";
+            names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProB] = "GostR3410-2001-CryptoPro-B";
+            names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProC] = "GostR3410-2001-CryptoPro-C";
+            names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchA] = "GostR3410-2001-CryptoPro-XchA";
+            names[CryptoProObjectIdentifiers.GostR3410x2001CryptoProXchB] = "GostR3410-2001-CryptoPro-XchB";
+        }
+
+        /**
+        * return the ECDomainParameters object for the given OID, null if it
+        * isn't present.
+        *
+        * @param oid an object identifier representing a named parameters, if present.
+        */
+        public static ECDomainParameters GetByOid(
+            DerObjectIdentifier oid)
+        {
+            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); }
+		}
+
+        public static ECDomainParameters GetByName(
+            string name)
+        {
+            DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name];
+
+            if (oid != null)
+            {
+                return (ECDomainParameters) parameters[oid];
+            }
+
+            return null;
+        }
+
+        /**
+        * return the named curve name represented by the given object identifier.
+        */
+        public static string GetName(
+            DerObjectIdentifier oid)
+        {
+            return (string) names[oid];
+        }
+
+		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
new file mode 100644
index 000000000..1d154cd27
--- /dev/null
+++ b/Crypto/src/asn1/ess/ESSCertIDv2.cs
@@ -0,0 +1,138 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.X509;
+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);
+		}
+
+	}
+}
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
new file mode 100644
index 000000000..a2aff4866
--- /dev/null
+++ b/Crypto/src/asn1/ess/SigningCertificateV2.cs
@@ -0,0 +1,106 @@
+using System;
+
+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);
+		}
+	}
+}
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
new file mode 100644
index 000000000..f322ef88f
--- /dev/null
+++ 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
new file mode 100644
index 000000000..3b4c59df2
--- /dev/null
+++ b/Crypto/src/asn1/nist/NISTNamedCurves.cs
@@ -0,0 +1,102 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Utilities;
+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()
+		{
+		}
+
+		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);
+		}
+
+		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);
+		}
+
+		public static X9ECParameters GetByName(
+			string name)
+		{
+			DerObjectIdentifier oid = (DerObjectIdentifier) objIds[name.ToUpperInvariant()];
+
+			if (oid != null)
+			{
+				return GetByOid(oid);
+			}
+
+			return null;
+		}
+
+		/**
+		* return the X9ECParameters object for the named curve represented by
+		* the passed in object identifier. Null if the curve isn't present.
+		*
+		* @param oid an object identifier representing a named curve, if present.
+		*/
+		public static X9ECParameters GetByOid(
+			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 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/nist/NISTObjectIdentifiers.cs b/Crypto/src/asn1/nist/NISTObjectIdentifiers.cs
new file mode 100644
index 000000000..f3957062f
--- /dev/null
+++ b/Crypto/src/asn1/nist/NISTObjectIdentifiers.cs
@@ -0,0 +1,61 @@
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Nist
+{
+    public sealed class NistObjectIdentifiers
+    {
+		private NistObjectIdentifiers()
+		{
+		}
+
+        //
+        // NIST
+        //     iso/itu(2) joint-assign(16) us(840) organization(1) gov(101) csor(3)
+
+        //
+        // nistalgorithms(4)
+        //
+        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 Aes = new DerObjectIdentifier(NistAlgorithm + ".1");
+
+        public static readonly DerObjectIdentifier IdAes128Ecb	= new DerObjectIdentifier(Aes + ".1");
+        public static readonly DerObjectIdentifier IdAes128Cbc	= new DerObjectIdentifier(Aes + ".2");
+        public static readonly DerObjectIdentifier IdAes128Ofb	= new DerObjectIdentifier(Aes + ".3");
+        public static readonly DerObjectIdentifier IdAes128Cfb	= new DerObjectIdentifier(Aes + ".4");
+        public static readonly DerObjectIdentifier IdAes128Wrap	= new DerObjectIdentifier(Aes + ".5");
+        public static readonly DerObjectIdentifier IdAes128Gcm	= new DerObjectIdentifier(Aes + ".6");
+        public static readonly DerObjectIdentifier IdAes128Ccm	= new DerObjectIdentifier(Aes + ".7");
+
+        public static readonly DerObjectIdentifier IdAes192Ecb	= new DerObjectIdentifier(Aes + ".21");
+        public static readonly DerObjectIdentifier IdAes192Cbc	= new DerObjectIdentifier(Aes + ".22");
+        public static readonly DerObjectIdentifier IdAes192Ofb	= new DerObjectIdentifier(Aes + ".23");
+        public static readonly DerObjectIdentifier IdAes192Cfb	= new DerObjectIdentifier(Aes + ".24");
+        public static readonly DerObjectIdentifier IdAes192Wrap	= new DerObjectIdentifier(Aes + ".25");
+        public static readonly DerObjectIdentifier IdAes192Gcm	= new DerObjectIdentifier(Aes + ".26");
+        public static readonly DerObjectIdentifier IdAes192Ccm	= new DerObjectIdentifier(Aes + ".27");
+
+        public static readonly DerObjectIdentifier IdAes256Ecb	= new DerObjectIdentifier(Aes + ".41");
+        public static readonly DerObjectIdentifier IdAes256Cbc	= new DerObjectIdentifier(Aes + ".42");
+        public static readonly DerObjectIdentifier IdAes256Ofb	= new DerObjectIdentifier(Aes + ".43");
+        public static readonly DerObjectIdentifier IdAes256Cfb	= new DerObjectIdentifier(Aes + ".44");
+        public static readonly DerObjectIdentifier IdAes256Wrap	= new DerObjectIdentifier(Aes + ".45");
+        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");
+
+		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
new file mode 100644
index 000000000..78213c138
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/ContentInfo.cs
@@ -0,0 +1,80 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class ContentInfo
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	contentType;
+        private readonly Asn1Encodable			content;
+
+		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");
+        }
+
+		private ContentInfo(
+            Asn1Sequence seq)
+        {
+			contentType = (DerObjectIdentifier) seq[0];
+
+			if (seq.Count > 1)
+			{
+				content = ((Asn1TaggedObject) seq[1]).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/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
new file mode 100644
index 000000000..645bb867c
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/PBES2Parameters.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class PbeS2Parameters
+        : Asn1Encodable
+    {
+        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);
+
+			throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+		}
+
+		public PbeS2Parameters(
+            Asn1Sequence seq)
+        {
+			if (seq.Count != 2)
+				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+
+			Asn1Sequence funcSeq = (Asn1Sequence)seq[0].ToAsn1Object();
+
+			// 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]));
+			}
+            else
+            {
+                func = new KeyDerivationFunc(funcSeq);
+            }
+
+			scheme = EncryptionScheme.GetInstance(seq[1].ToAsn1Object());
+        }
+
+		public KeyDerivationFunc KeyDerivationFunc
+		{
+			get { return func; }
+		}
+
+		public EncryptionScheme EncryptionScheme
+		{
+			get { return scheme; }
+		}
+
+		public override Asn1Object ToAsn1Object()
+        {
+			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
new file mode 100644
index 000000000..bd0ef7d1e
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/PrivateKeyInfo.cs
@@ -0,0 +1,126 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class PrivateKeyInfo
+        : Asn1Encodable
+    {
+        private readonly Asn1Object				privKey;
+        private readonly AlgorithmIdentifier	algID;
+		private readonly Asn1Set				attributes;
+
+		public static PrivateKeyInfo GetInstance(
+			object obj)
+		{
+			if (obj is PrivateKeyInfo)
+				return (PrivateKeyInfo) obj;
+
+			if (obj != null)
+				return new PrivateKeyInfo(Asn1Sequence.GetInstance(obj));
+
+			return null;
+		}
+
+		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)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            BigInteger version = ((DerInteger) e.Current).Value;
+            if (version.IntValue != 0)
+            {
+                throw new ArgumentException("wrong version for private key info");
+            }
+
+			e.MoveNext();
+            algID = AlgorithmIdentifier.GetInstance(e.Current);
+
+			try
+            {
+				e.MoveNext();
+				Asn1OctetString data = (Asn1OctetString) e.Current;
+
+				privKey = Asn1Object.FromByteArray(data.GetOctets());
+            }
+            catch (IOException)
+            {
+				throw new ArgumentException("Error recoverying private key from sequence");
+            }
+
+			if (e.MoveNext())
+			{
+				attributes = Asn1Set.GetInstance((Asn1TaggedObject) e.Current, false);
+			}
+		}
+
+		public AlgorithmIdentifier AlgorithmID
+		{
+			get { return algID; }
+		}
+
+		public Asn1Object PrivateKey
+		{
+			get { return privKey; }
+		}
+
+    	public Asn1Set Attributes
+    	{
+    		get { return attributes; }
+    	}
+
+		/**
+         * write out an RSA private key with its associated information
+         * as described in Pkcs8.
+         * <pre>
+         *      PrivateKeyInfo ::= Sequence {
+         *                              version Version,
+         *                              privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
+         *                              privateKey PrivateKey,
+         *                              attributes [0] IMPLICIT Attributes OPTIONAL
+         *                          }
+         *      Version ::= Integer {v1(0)} (v1,...)
+         *
+         *      PrivateKey ::= OCTET STRING
+         *
+         *      Attributes ::= Set OF Attr
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			Asn1EncodableVector v = new Asn1EncodableVector(
+				new DerInteger(0),
+				algID,
+				new DerOctetString(privKey));
+
+			if (attributes != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, attributes));
+			}
+
+			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
new file mode 100644
index 000000000..dbb07c744
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/RSAPrivateKeyStructure.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class RsaPrivateKeyStructure
+        : Asn1Encodable
+    {
+        private readonly BigInteger	modulus;
+        private readonly BigInteger	publicExponent;
+        private readonly BigInteger	privateExponent;
+        private readonly BigInteger	prime1;
+        private readonly BigInteger	prime2;
+        private readonly BigInteger	exponent1;
+        private readonly BigInteger	exponent2;
+        private readonly BigInteger	coefficient;
+
+		public RsaPrivateKeyStructure(
+            BigInteger	modulus,
+            BigInteger	publicExponent,
+            BigInteger	privateExponent,
+            BigInteger	prime1,
+            BigInteger	prime2,
+            BigInteger	exponent1,
+            BigInteger	exponent2,
+            BigInteger	coefficient)
+        {
+            this.modulus = modulus;
+            this.publicExponent = publicExponent;
+            this.privateExponent = privateExponent;
+            this.prime1 = prime1;
+            this.prime2 = prime2;
+            this.exponent1 = exponent1;
+            this.exponent2 = exponent2;
+            this.coefficient = coefficient;
+        }
+
+		public RsaPrivateKeyStructure(
+            Asn1Sequence seq)
+        {
+			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; }
+		}
+
+		/**
+         * This outputs the key in Pkcs1v2 format.
+         * <pre>
+         *      RsaPrivateKey ::= Sequence {
+         *                          version Version,
+         *                          modulus Integer, -- n
+         *                          publicExponent Integer, -- e
+         *                          privateExponent Integer, -- d
+         *                          prime1 Integer, -- p
+         *                          prime2 Integer, -- q
+         *                          exponent1 Integer, -- d mod (p-1)
+         *                          exponent2 Integer, -- d mod (q-1)
+         *                          coefficient Integer -- (inverse of q) mod p
+         *                      }
+         *
+         *      Version ::= Integer
+         * </pre>
+         * <p>This routine is written to output Pkcs1 version 0, private keys.</p>
+         */
+        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));
+        }
+    }
+}
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
new file mode 100644
index 000000000..10951d37a
--- /dev/null
+++ b/Crypto/src/asn1/pkcs/SignedData.cs
@@ -0,0 +1,163 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    /**
+     * a Pkcs#7 signed data object.
+     */
+    public class SignedData
+        : Asn1Encodable
+    {
+        private readonly DerInteger		version;
+        private readonly Asn1Set		digestAlgorithms;
+        private readonly ContentInfo	contentInfo;
+        private readonly Asn1Set		certificates;
+        private readonly Asn1Set		crls;
+        private readonly Asn1Set		signerInfos;
+
+		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");
+		}
+
+		public SignedData(
+            DerInteger        _version,
+            Asn1Set           _digestAlgorithms,
+            ContentInfo       _contentInfo,
+            Asn1Set           _certificates,
+            Asn1Set           _crls,
+            Asn1Set           _signerInfos)
+        {
+            version          = _version;
+            digestAlgorithms = _digestAlgorithms;
+            contentInfo      = _contentInfo;
+            certificates     = _certificates;
+            crls             = _crls;
+            signerInfos      = _signerInfos;
+        }
+
+		private SignedData(
+            Asn1Sequence seq)
+        {
+            IEnumerator e = seq.GetEnumerator();
+
+			e.MoveNext();
+            version = (DerInteger) e.Current;
+
+			e.MoveNext();
+            digestAlgorithms = (Asn1Set) e.Current;
+
+			e.MoveNext();
+            contentInfo = ContentInfo.GetInstance(e.Current);
+
+			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.
+                //
+                if (o is DerTaggedObject)
+                {
+                    DerTaggedObject tagged = (DerTaggedObject) o;
+
+					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);
+                    }
+                }
+                else
+                {
+                    signerInfos = (Asn1Set) o;
+                }
+            }
+        }
+
+		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 {
+         *      version Version,
+         *      digestAlgorithms DigestAlgorithmIdentifiers,
+         *      contentInfo ContentInfo,
+         *      certificates
+         *          [0] IMPLICIT ExtendedCertificatesAndCertificates
+         *                   OPTIONAL,
+         *      crls
+         *          [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+         *      signerInfos SignerInfos }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				version, digestAlgorithms, contentInfo);
+
+			if (certificates != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, certificates));
+            }
+
+			if (crls != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, crls));
+            }
+
+			v.Add(signerInfos);
+
+			return new BerSequence(v);
+        }
+    }
+}
diff --git a/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
new file mode 100644
index 000000000..2e9c27fd2
--- /dev/null
+++ b/Crypto/src/asn1/sec/ECPrivateKeyStructure.cs
@@ -0,0 +1,118 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+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;
+		}
+	}
+}
diff --git a/Crypto/src/asn1/sec/SECNamedCurves.cs b/Crypto/src/asn1/sec/SECNamedCurves.cs
new file mode 100644
index 000000000..c7503144f
--- /dev/null
+++ b/Crypto/src/asn1/sec/SECNamedCurves.cs
@@ -0,0 +1,1192 @@
+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.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();
+        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); }
+		}
+	}
+}
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
new file mode 100644
index 000000000..adf254e56
--- /dev/null
+++ b/Crypto/src/asn1/smime/SMIMECapabilities.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.Smime
+{
+    /**
+     * Handler class for dealing with S/MIME Capabilities
+     */
+    public class SmimeCapabilities
+        : Asn1Encodable
+    {
+        /**
+         * general preferences
+         */
+        public static readonly DerObjectIdentifier PreferSignedData = PkcsObjectIdentifiers.PreferSignedData;
+        public static readonly DerObjectIdentifier CannotDecryptAny = PkcsObjectIdentifiers.CannotDecryptAny;
+        public static readonly DerObjectIdentifier SmimeCapabilitesVersions = 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 Asn1Sequence capabilities;
+
+		/**
+         * 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 SmimeCapabilities GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is SmimeCapabilities)
+            {
+                return (SmimeCapabilities) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new SmimeCapabilities((Asn1Sequence) obj);
+            }
+
+			if (obj is AttributeX509)
+            {
+                return new SmimeCapabilities(
+                    (Asn1Sequence)(((AttributeX509) obj).AttrValues[0]));
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public SmimeCapabilities(
+            Asn1Sequence seq)
+        {
+            capabilities = seq;
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete("Use 'GetCapabilitiesForOid' instead")]
+        public ArrayList GetCapabilities(
+            DerObjectIdentifier capability)
+        {
+            ArrayList list = new ArrayList();
+            DoGetCapabilitiesForOid(capability, list);
+			return list;
+        }
+#endif
+
+        /**
+         * returns an ArrayList with 0 or more objects of all the capabilities
+         * matching the passed in capability Oid. If the Oid passed is null the
+         * entire set is returned.
+         */
+        public IList GetCapabilitiesForOid(
+            DerObjectIdentifier capability)
+        {
+            IList list = Platform.CreateArrayList();
+            DoGetCapabilitiesForOid(capability, list);
+			return list;
+        }
+
+        private void DoGetCapabilitiesForOid(DerObjectIdentifier capability, IList list)
+        {
+			if (capability == null)
+            {
+				foreach (object o in capabilities)
+				{
+                    SmimeCapability cap = SmimeCapability.GetInstance(o);
+
+					list.Add(cap);
+                }
+            }
+            else
+            {
+				foreach (object o in capabilities)
+				{
+                    SmimeCapability cap = SmimeCapability.GetInstance(o);
+
+					if (capability.Equals(cap.CapabilityID))
+                    {
+                        list.Add(cap);
+                    }
+                }
+            }
+        }
+
+        /**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * SMIMECapabilities ::= Sequence OF SMIMECapability
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return capabilities;
+        }
+    }
+}
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
new file mode 100644
index 000000000..0cfdb8483
--- /dev/null
+++ b/Crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
@@ -0,0 +1,428 @@
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+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();
+        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");
+		}
+	}
+}
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
new file mode 100644
index 000000000..43d485500
--- /dev/null
+++ b/Crypto/src/asn1/util/Asn1Dump.cs
@@ -0,0 +1,378 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.Utilities
+{
+    public sealed class Asn1Dump
+    {
+		private static readonly string NewLine = Platform.NewLine;
+
+		private Asn1Dump()
+        {
+        }
+
+        private const string Tab = "    ";
+        private const int SampleSize = 32;
+
+        /**
+         * dump a Der object as a formatted string with indentation
+         *
+         * @param obj the Asn1Object to be dumped out.
+         */
+        private static void AsString(
+            string			indent,
+            bool			verbose,
+            Asn1Object		obj,
+			StringBuilder	buf)
+        {
+            if (obj is Asn1Sequence)
+            {
+				string tab = indent + Tab;
+				buf.Append(indent);
+                if (obj is BerSequence)
+                {
+                    buf.Append("BER Sequence");
+                }
+                else if (obj is DerSequence)
+                {
+                    buf.Append("DER Sequence");
+                }
+                else
+                {
+                    buf.Append("Sequence");
+                }
+
+                buf.Append(NewLine);
+
+				foreach (Asn1Encodable o in ((Asn1Sequence)obj))
+				{
+                    if (o == null || o is Asn1Null)
+                    {
+                        buf.Append(tab);
+                        buf.Append("NULL");
+                        buf.Append(NewLine);
+                    }
+                    else
+                    {
+                        AsString(tab, verbose, o.ToAsn1Object(), buf);
+                    }
+                }
+            }
+            else if (obj is DerTaggedObject)
+            {
+                string tab = indent + Tab;
+				buf.Append(indent);
+                if (obj is BerTaggedObject)
+                {
+                    buf.Append("BER Tagged [");
+                }
+                else
+                {
+                    buf.Append("Tagged [");
+                }
+
+				DerTaggedObject o = (DerTaggedObject)obj;
+
+				buf.Append(((int)o.TagNo).ToString());
+                buf.Append(']');
+
+				if (!o.IsExplicit())
+                {
+                    buf.Append(" IMPLICIT ");
+                }
+
+				buf.Append(NewLine);
+
+				if (o.IsEmpty())
+                {
+                    buf.Append(tab);
+                    buf.Append("EMPTY");
+                    buf.Append(NewLine);
+                }
+                else
+                {
+                    AsString(tab, verbose, o.GetObject(), buf);
+                }
+            }
+            else if (obj is BerSet)
+            {
+                string tab = indent + Tab;
+
+				buf.Append(indent);
+                buf.Append("BER Set");
+                buf.Append(NewLine);
+
+				foreach (Asn1Encodable o in ((Asn1Set)obj))
+				{
+                    if (o == null)
+                    {
+                        buf.Append(tab);
+                        buf.Append("NULL");
+                        buf.Append(NewLine);
+                    }
+                    else
+                    {
+                        AsString(tab, verbose, o.ToAsn1Object(), buf);
+                    }
+                }
+            }
+            else if (obj is DerSet)
+            {
+                string tab = indent + Tab;
+
+				buf.Append(indent);
+                buf.Append("DER Set");
+                buf.Append(NewLine);
+
+				foreach (Asn1Encodable o in ((Asn1Set)obj))
+				{
+                    if (o == null)
+                    {
+                        buf.Append(tab);
+                        buf.Append("NULL");
+                        buf.Append(NewLine);
+                    }
+                    else
+                    {
+                        AsString(tab, verbose, o.ToAsn1Object(), buf);
+                    }
+                }
+            }
+            else if (obj is DerObjectIdentifier)
+            {
+                buf.Append(indent + "ObjectIdentifier(" + ((DerObjectIdentifier)obj).Id + ")" + NewLine);
+            }
+            else if (obj is DerBoolean)
+            {
+                buf.Append(indent + "Boolean(" + ((DerBoolean)obj).IsTrue + ")" + NewLine);
+            }
+            else if (obj is DerInteger)
+            {
+                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 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);
+			}
+            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 DerPrintableString)
+            {
+                buf.Append(indent + "PrintableString(" + ((DerPrintableString)obj).GetString() + ") " + NewLine);
+            }
+            else if (obj is DerVisibleString)
+            {
+                buf.Append(indent + "VisibleString(" + ((DerVisibleString)obj).GetString() + ") " + NewLine);
+            }
+            else if (obj is DerBmpString)
+            {
+                buf.Append(indent + "BMPString(" + ((DerBmpString)obj).GetString() + ") " + NewLine);
+            }
+            else if (obj is DerT61String)
+            {
+                buf.Append(indent + "T61String(" + ((DerT61String)obj).GetString() + ") " + NewLine);
+            }
+            else if (obj is DerUtcTime)
+            {
+                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)
+            {
+				string hex = Hex.ToHexString(((DerUnknownTag)obj).GetData());
+                buf.Append(indent + "Unknown " + ((int)((DerUnknownTag)obj).Tag).ToString("X") + " " + hex + NewLine);
+            }
+            else if (obj is BerApplicationSpecific)
+            {
+                buf.Append(outputApplicationSpecific("BER", indent, verbose, (BerApplicationSpecific)obj));
+            }
+            else if (obj is DerApplicationSpecific)
+            {
+                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);
+                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);
+			}
+            else
+            {
+                buf.Append(indent + obj.ToString() + NewLine);
+            }
+        }
+
+        private static string outputApplicationSpecific(
+            string					type,
+            string					indent,
+            bool					verbose,
+            DerApplicationSpecific	app)
+        {
+            StringBuilder buf = new StringBuilder();
+
+            if (app.IsConstructed())
+            {
+                try
+                {
+                    Asn1Sequence s = Asn1Sequence.GetInstance(app.GetObject(Asn1Tags.Sequence));
+                    buf.Append(indent + type + " ApplicationSpecific[" + app.ApplicationTag + "]" + NewLine);
+                    foreach (Asn1Encodable ae in s)
+                    {
+                    	AsString(indent + Tab, verbose, ae.ToAsn1Object(), buf);
+                    }
+                }
+                catch (IOException e)
+                {
+                    buf.Append(e);
+                }
+                return buf.ToString();
+            }
+
+            return indent + type + " ApplicationSpecific[" + app.ApplicationTag + "] ("
+                + Hex.ToHexString(app.GetContents()) + ")" + NewLine;
+        }
+
+		[Obsolete("Use version accepting Asn1Encodable")]
+		public static string DumpAsString(
+            object   obj)
+        {
+            if (obj is Asn1Encodable)
+            {
+				StringBuilder buf = new StringBuilder();
+                AsString("", false, ((Asn1Encodable)obj).ToAsn1Object(), buf);
+				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 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;
+
+			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);
+				}
+			}
+
+			return buf.ToString();
+		}
+
+		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);
+				}
+			}
+
+			return buf.ToString();
+		}
+    }
+}
diff --git a/Crypto/src/asn1/util/Dump.cs b/Crypto/src/asn1/util/Dump.cs
new file mode 100644
index 000000000..2712ca1b3
--- /dev/null
+++ b/Crypto/src/asn1/util/Dump.cs
@@ -0,0 +1,30 @@
+#if !PORTABLE
+using Org.BouncyCastle.Asn1;
+
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.Utilities
+{
+    public sealed class Dump
+    {
+        private Dump()
+        {
+        }
+
+        public static void Main(string[] args)
+        {
+            FileStream fIn = File.OpenRead(args[0]);
+            Asn1InputStream bIn = new Asn1InputStream(fIn);
+
+			Asn1Object obj;
+			while ((obj = bIn.ReadObject()) != null)
+            {
+                Console.WriteLine(Asn1Dump.DumpAsString(obj));
+            }
+
+			bIn.Dispose();
+        }
+    }
+}
+#endif
\ No newline at end of file
diff --git a/Crypto/src/asn1/util/FilterStream.cs b/Crypto/src/asn1/util/FilterStream.cs
new file mode 100644
index 000000000..f277e33e6
--- /dev/null
+++ b/Crypto/src/asn1/util/FilterStream.cs
@@ -0,0 +1,72 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Asn1.Utilities
+{
+    public class FilterStream : Stream
+    {
+        public FilterStream(Stream s)
+        {
+            this.s = s;
+        }
+        public override bool CanRead
+        {
+            get { return s.CanRead; }
+        }
+        public override bool CanSeek
+        {
+            get { return s.CanSeek; }
+        }
+        public override bool CanWrite
+        {
+            get { return s.CanWrite; }
+        }
+        public override long Length
+        {
+            get { return s.Length; }
+        }
+        public override long Position
+        {
+            get { return s.Position; }
+            set { s.Position = value; }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                s.Dispose();
+            }
+        }
+
+        public override void Flush()
+        {
+            s.Flush();
+        }
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            return s.Seek(offset, origin);
+        }
+        public override void SetLength(long value)
+        {
+            s.SetLength(value);
+        }
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            return s.Read(buffer, offset, count);
+        }
+        public override int ReadByte()
+        {
+            return s.ReadByte();
+        }
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            s.Write(buffer, offset, count);
+        }
+        public override void WriteByte(byte value)
+        {
+            s.WriteByte(value);
+        }
+        protected readonly Stream s;
+    }
+}
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
new file mode 100644
index 000000000..caf9e77c9
--- /dev/null
+++ b/Crypto/src/asn1/x509/AlgorithmIdentifier.cs
@@ -0,0 +1,110 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AlgorithmIdentifier
+        : Asn1Encodable
+    {
+        private readonly DerObjectIdentifier	objectID;
+        private readonly Asn1Encodable			parameters;
+		private readonly bool					parametersDefined;
+
+		public static AlgorithmIdentifier GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static AlgorithmIdentifier GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is AlgorithmIdentifier)
+                return (AlgorithmIdentifier) obj;
+
+			if (obj is DerObjectIdentifier)
+                return new AlgorithmIdentifier((DerObjectIdentifier) obj);
+
+			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");
+		}
+
+		public AlgorithmIdentifier(
+            DerObjectIdentifier objectID)
+        {
+            this.objectID = objectID;
+        }
+
+		public AlgorithmIdentifier(
+            string objectID)
+        {
+            this.objectID = new DerObjectIdentifier(objectID);
+        }
+
+		public AlgorithmIdentifier(
+            DerObjectIdentifier	objectID,
+            Asn1Encodable		parameters)
+        {
+            this.objectID = objectID;
+            this.parameters = parameters;
+			this.parametersDefined = true;
+        }
+
+		internal AlgorithmIdentifier(
+            Asn1Sequence seq)
+        {
+			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);
+
+			if (parametersDefined)
+            {
+                this.parameters = seq[1];
+            }
+        }
+
+		public virtual DerObjectIdentifier ObjectID
+		{
+			get { return objectID; }
+		}
+
+		public Asn1Encodable Parameters
+		{
+			get { return parameters; }
+		}
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *      AlgorithmIdentifier ::= Sequence {
+         *                            algorithm OBJECT IDENTIFIER,
+         *                            parameters ANY DEFINED BY algorithm OPTIONAL }
+         * </pre>
+         */
+        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);
+        }
+    }
+}
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
new file mode 100644
index 000000000..87b112f01
--- /dev/null
+++ b/Crypto/src/asn1/x509/AttributeTable.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class AttributeTable
+    {
+        private readonly IDictionary attributes;
+
+        public AttributeTable(
+            IDictionary attrs)
+        {
+            this.attributes = Platform.CreateHashtable(attrs);
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public AttributeTable(
+            Hashtable attrs)
+        {
+            this.attributes = Platform.CreateHashtable(attrs);
+        }
+#endif
+
+        public AttributeTable(
+            Asn1EncodableVector v)
+        {
+            this.attributes = Platform.CreateHashtable(v.Count);
+
+			for (int i = 0; i != v.Count; i++)
+            {
+                AttributeX509 a = AttributeX509.GetInstance(v[i]);
+
+				attributes.Add(a.AttrType, a);
+            }
+        }
+
+		public AttributeTable(
+            Asn1Set s)
+        {
+            this.attributes = Platform.CreateHashtable(s.Count);
+
+			for (int i = 0; i != s.Count; i++)
+            {
+                AttributeX509 a = AttributeX509.GetInstance(s[i]);
+
+				attributes.Add(a.AttrType, a);
+            }
+        }
+
+		public AttributeX509 Get(
+            DerObjectIdentifier oid)
+        {
+            return (AttributeX509) attributes[oid];
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete("Use 'ToDictionary' instead")]
+		public Hashtable ToHashtable()
+        {
+            return new Hashtable(attributes);
+        }
+#endif
+
+        public IDictionary ToDictionary()
+        {
+            return Platform.CreateHashtable(attributes);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x509/AuthorityInformationAccess.cs b/Crypto/src/asn1/x509/AuthorityInformationAccess.cs
new file mode 100644
index 000000000..3eeba8cd2
--- /dev/null
+++ b/Crypto/src/asn1/x509/AuthorityInformationAccess.cs
@@ -0,0 +1,105 @@
+using System;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+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();
+		}
+	}
+}
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/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
new file mode 100644
index 000000000..3bf79f392
--- /dev/null
+++ b/Crypto/src/asn1/x509/ExtendedKeyUsage.cs
@@ -0,0 +1,131 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * The extendedKeyUsage object.
+     * <pre>
+     *      extendedKeyUsage ::= Sequence SIZE (1..MAX) OF KeyPurposeId
+     * </pre>
+     */
+    public class ExtendedKeyUsage
+        : Asn1Encodable
+    {
+        internal readonly IDictionary usageTable = Platform.CreateHashtable();
+        internal readonly Asn1Sequence seq;
+
+		public static ExtendedKeyUsage GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static ExtendedKeyUsage GetInstance(
+            object obj)
+        {
+            if (obj is ExtendedKeyUsage)
+            {
+                return (ExtendedKeyUsage) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new ExtendedKeyUsage((Asn1Sequence) obj);
+            }
+
+			if (obj is X509Extension)
+			{
+				return GetInstance(X509Extension.ConvertValueToObject((X509Extension) obj));
+			}
+
+			throw new ArgumentException("Invalid ExtendedKeyUsage: " + obj.GetType().Name);
+        }
+
+		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.");
+
+				this.usageTable.Add(o, o);
+            }
+        }
+
+		public ExtendedKeyUsage(
+			params KeyPurposeID[] usages)
+		{
+			this.seq = new DerSequence(usages);
+
+			foreach (KeyPurposeID usage in usages)
+			{
+				this.usageTable.Add(usage, usage);
+			}
+		}
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public ExtendedKeyUsage(
+            ArrayList usages)
+            : this((IEnumerable)usages)
+        {
+        }
+#endif
+
+        public ExtendedKeyUsage(
+            IEnumerable usages)
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			foreach (Asn1Object o in usages)
+            {
+				v.Add(o);
+
+				this.usageTable.Add(o, o);
+            }
+
+			this.seq = new DerSequence(v);
+        }
+
+		public bool HasKeyPurposeId(
+            KeyPurposeID keyPurposeId)
+        {
+            return usageTable[keyPurposeId] != null;
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete("Use 'GetAllUsages'")]
+        public ArrayList GetUsages()
+        {
+            return new ArrayList(usageTable.Values);
+        }
+#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);
+		}
+
+        public int Count
+		{
+			get { return usageTable.Count; }
+		}
+
+		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
new file mode 100644
index 000000000..c178f5b45
--- /dev/null
+++ b/Crypto/src/asn1/x509/NameConstraints.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	public class NameConstraints
+		: Asn1Encodable
+	{
+		private Asn1Sequence permitted, excluded;
+
+		public static NameConstraints GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is NameConstraints)
+			{
+				return (NameConstraints) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new NameConstraints((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		public NameConstraints(
+			Asn1Sequence seq)
+		{
+			foreach (Asn1TaggedObject o in seq)
+			{
+				switch (o.TagNo)
+				{
+					case 0:
+						permitted = Asn1Sequence.GetInstance(o, false);
+						break;
+					case 1:
+						excluded = Asn1Sequence.GetInstance(o, false);
+						break;
+				}
+			}
+		}
+
+#if !(SILVERLIGHT || PORTABLE)
+        public NameConstraints(
+            ArrayList permitted,
+            ArrayList excluded)
+            : this((IList)permitted, (IList)excluded)
+        {
+        }
+#endif
+
+        /**
+		 * Constructor from a given details.
+		 *
+		 * <p>permitted and excluded are Vectors of GeneralSubtree objects.</p>
+		 *
+		 * @param permitted Permitted subtrees
+		 * @param excluded Excluded subtrees
+		 */
+		public NameConstraints(
+			IList   permitted,
+			IList   excluded)
+		{
+			if (permitted != null)
+			{
+				this.permitted = CreateSequence(permitted);
+			}
+
+			if (excluded != null)
+			{
+				this.excluded = CreateSequence(excluded);
+			}
+		}
+
+		private DerSequence CreateSequence(
+			IList subtrees)
+		{
+            GeneralSubtree[] gsts = new GeneralSubtree[subtrees.Count];
+            for (int i = 0; i < subtrees.Count; ++i)
+            {
+                gsts[i] = (GeneralSubtree)subtrees[i];
+            }
+            return new DerSequence(gsts);
+		}
+
+		public Asn1Sequence PermittedSubtrees
+		{
+			get { return permitted; }
+		}
+
+		public Asn1Sequence ExcludedSubtrees
+		{
+			get { return excluded; }
+		}
+
+		/*
+		 * NameConstraints ::= SEQUENCE { permittedSubtrees [0] GeneralSubtrees
+		 * OPTIONAL, excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (permitted != null)
+			{
+				v.Add(new DerTaggedObject(false, 0, permitted));
+			}
+
+			if (excluded != null)
+			{
+				v.Add(new DerTaggedObject(false, 1, excluded));
+			}
+
+			return new DerSequence(v);
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/NoticeReference.cs b/Crypto/src/asn1/x509/NoticeReference.cs
new file mode 100644
index 000000000..718fe92cf
--- /dev/null
+++ b/Crypto/src/asn1/x509/NoticeReference.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections;
+
+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)
+        {
+        }
+#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);
+		}
+	}
+}
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
new file mode 100644
index 000000000..928ad134d
--- /dev/null
+++ b/Crypto/src/asn1/x509/PolicyMappings.cs
@@ -0,0 +1,70 @@
+using System.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * PolicyMappings V3 extension, described in RFC3280.
+	 * <pre>
+	 *    PolicyMappings ::= Sequence SIZE (1..MAX) OF Sequence {
+	 *      issuerDomainPolicy      CertPolicyId,
+	 *      subjectDomainPolicy     CertPolicyId }
+	 * </pre>
+	 *
+	 * @see <a href="http://www.faqs.org/rfc/rfc3280.txt">RFC 3280, section 4.2.1.6</a>
+	 */
+	public class PolicyMappings
+		: Asn1Encodable
+	{
+		private readonly Asn1Sequence seq;
+
+		/**
+		 * Creates a new <code>PolicyMappings</code> instance.
+		 *
+		 * @param seq an <code>Asn1Sequence</code> constructed as specified
+		 * in RFC 3280
+		 */
+		public PolicyMappings(
+			Asn1Sequence seq)
+		{
+			this.seq = seq;
+		}
+
+#if !(SILVERLIGHT || PORTABLE)
+        public PolicyMappings(
+            Hashtable mappings)
+            : this((IDictionary)mappings)
+        {
+        }
+#endif
+
+        /**
+		 * Creates a new <code>PolicyMappings</code> instance.
+		 *
+		 * @param mappings a <code>HashMap</code> value that maps
+		 * <code>string</code> oids
+		 * to other <code>string</code> oids.
+		 */
+		public PolicyMappings(
+			IDictionary mappings)
+		{
+			Asn1EncodableVector v = new Asn1EncodableVector();
+
+			foreach (string idp in mappings.Keys)
+			{
+				string sdp = (string) mappings[idp];
+
+				v.Add(
+					new DerSequence(
+						new DerObjectIdentifier(idp),
+						new DerObjectIdentifier(sdp)));
+			}
+
+			seq = new DerSequence(v);
+		}
+
+		public override Asn1Object ToAsn1Object()
+		{
+			return seq;
+		}
+	}
+}
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
new file mode 100644
index 000000000..187f8d3bb
--- /dev/null
+++ b/Crypto/src/asn1/x509/PolicyQualifierInfo.cs
@@ -0,0 +1,91 @@
+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;
+
+		/**
+		 * 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> 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];
+		}
+
+		public static PolicyQualifierInfo GetInstance(
+			object obj)
+		{
+			if (obj is PolicyQualifierInfo)
+			{
+				return (PolicyQualifierInfo) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new PolicyQualifierInfo((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in GetInstance: " + obj.GetType().FullName, "obj");
+		}
+
+		/**
+		 * 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
new file mode 100644
index 000000000..c76d94d78
--- /dev/null
+++ b/Crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
@@ -0,0 +1,142 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+	/**
+	 * This extension may contain further X.500 attributes of the subject. See also
+	 * RFC 3039.
+	 *
+	 * <pre>
+	 *     SubjectDirectoryAttributes ::= Attributes
+	 *     Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+	 *     Attribute ::= SEQUENCE
+	 *     {
+	 *       type AttributeType
+	 *       values SET OF AttributeValue
+	 *     }
+	 *
+	 *     AttributeType ::= OBJECT IDENTIFIER
+	 *     AttributeValue ::= ANY DEFINED BY AttributeType
+	 * </pre>
+	 *
+	 * @see org.bouncycastle.asn1.x509.X509Name for AttributeType ObjectIdentifiers.
+	 */
+	public class SubjectDirectoryAttributes
+		: Asn1Encodable
+	{
+		private readonly IList attributes;
+
+		public static SubjectDirectoryAttributes GetInstance(
+			object obj)
+		{
+			if (obj == null || obj is SubjectDirectoryAttributes)
+			{
+				return (SubjectDirectoryAttributes) obj;
+			}
+
+			if (obj is Asn1Sequence)
+			{
+				return new SubjectDirectoryAttributes((Asn1Sequence) obj);
+			}
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+		 * Constructor from Asn1Sequence.
+		 *
+		 * The sequence is of type SubjectDirectoryAttributes:
+		 *
+		 * <pre>
+		 *      SubjectDirectoryAttributes ::= Attributes
+		 *      Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+		 *      Attribute ::= SEQUENCE
+		 *      {
+		 *        type AttributeType
+		 *        values SET OF AttributeValue
+		 *      }
+		 *
+		 *      AttributeType ::= OBJECT IDENTIFIER
+		 *      AttributeValue ::= ANY DEFINED BY AttributeType
+		 * </pre>
+		 *
+		 * @param seq
+		 *            The ASN.1 sequence.
+		 */
+		private SubjectDirectoryAttributes(
+			Asn1Sequence seq)
+		{
+            this.attributes = Platform.CreateArrayList();
+            foreach (object o in seq)
+			{
+				Asn1Sequence s = Asn1Sequence.GetInstance(o);
+				attributes.Add(AttributeX509.GetInstance(s));
+			}
+		}
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public SubjectDirectoryAttributes(
+            ArrayList attributes)
+            : this((IList)attributes)
+        {
+        }
+#endif
+
+        /**
+		 * Constructor from an ArrayList of attributes.
+		 *
+		 * The ArrayList consists of attributes of type {@link Attribute Attribute}
+		 *
+		 * @param attributes The attributes.
+		 *
+		 */
+		public SubjectDirectoryAttributes(
+			IList attributes)
+		{
+            this.attributes = Platform.CreateArrayList(attributes);
+        }
+
+		/**
+		 * Produce an object suitable for an Asn1OutputStream.
+		 *
+		 * Returns:
+		 *
+		 * <pre>
+		 *      SubjectDirectoryAttributes ::= Attributes
+		 *      Attributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+		 *      Attribute ::= SEQUENCE
+		 *      {
+		 *        type AttributeType
+		 *        values SET OF AttributeValue
+		 *      }
+		 *
+		 *      AttributeType ::= OBJECT IDENTIFIER
+		 *      AttributeValue ::= ANY DEFINED BY AttributeType
+		 * </pre>
+		 *
+		 * @return a DERObject
+		 */
+		public override Asn1Object ToAsn1Object()
+		{
+            AttributeX509[] v = new AttributeX509[attributes.Count];
+            for (int i = 0; i < attributes.Count; ++i)
+            {
+                v[i] = (AttributeX509)attributes[i];
+            }
+            return new DerSequence(v);
+		}
+
+        /**
+		 * @return Returns the attributes.
+		 */
+		public IEnumerable Attributes
+		{
+			get { return new EnumerableProxy(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
new file mode 100644
index 000000000..ca4e99ac7
--- /dev/null
+++ b/Crypto/src/asn1/x509/Time.cs
@@ -0,0 +1,120 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class Time
+        : Asn1Encodable, IAsn1Choice
+    {
+        internal Asn1Object time;
+
+		public static Time GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(obj.GetObject());
+        }
+
+		public Time(
+            Asn1Object time)
+        {
+			if (time == null)
+				throw new ArgumentNullException("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 = Int32.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 GetTime()
+        {
+            if (time is DerUtcTime)
+            {
+                return ((DerUtcTime) time).AdjustedTimeString;
+            }
+
+			return ((DerGeneralizedTime) time).GetTime();
+        }
+
+		/// <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);
+			}
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         * Time ::= CHOICE {
+         *             utcTime        UTCTime,
+         *             generalTime    GeneralizedTime }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return time;
+        }
+
+		public override string ToString()
+		{
+			return GetTime();
+		}
+	}
+}
diff --git a/Crypto/src/asn1/x509/UserNotice.cs b/Crypto/src/asn1/x509/UserNotice.cs
new file mode 100644
index 000000000..2878a180f
--- /dev/null
+++ b/Crypto/src/asn1/x509/UserNotice.cs
@@ -0,0 +1,104 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * <code>UserNotice</code> class, used in
+     * <code>CertificatePolicies</code> X509 extensions (in policy
+     * qualifiers).
+     * <pre>
+     * UserNotice ::= Sequence {
+     *      noticeRef        NoticeReference OPTIONAL,
+     *      explicitText     DisplayText OPTIONAL}
+     *
+     * </pre>
+     *
+     * @see PolicyQualifierId
+     * @see PolicyInformation
+     */
+    public class UserNotice
+        : Asn1Encodable
+    {
+        internal NoticeReference	noticeRef;
+        internal DisplayText		explicitText;
+
+		/**
+         * Creates a new <code>UserNotice</code> instance.
+         *
+         * @param noticeRef a <code>NoticeReference</code> value
+         * @param explicitText a <code>DisplayText</code> value
+         */
+        public UserNotice(
+            NoticeReference	noticeRef,
+            DisplayText		explicitText)
+        {
+            this.noticeRef = noticeRef;
+            this.explicitText = explicitText;
+        }
+
+		/**
+         * Creates a new <code>UserNotice</code> instance.
+         *
+         * @param noticeRef a <code>NoticeReference</code> value
+         * @param str the explicitText field as a string.
+         */
+        public UserNotice(
+            NoticeReference	noticeRef,
+            string			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);
+			}
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector av = new Asn1EncodableVector();
+
+			if (noticeRef != null)
+            {
+                av.Add(noticeRef);
+            }
+
+			if (explicitText != null)
+            {
+                av.Add(explicitText);
+            }
+
+			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
new file mode 100644
index 000000000..a9c43357c
--- /dev/null
+++ b/Crypto/src/asn1/x509/V2Form.cs
@@ -0,0 +1,125 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class V2Form
+        : Asn1Encodable
+    {
+        internal GeneralNames        issuerName;
+        internal IssuerSerial        baseCertificateID;
+        internal ObjectDigestInfo    objectDigestInfo;
+
+		public static V2Form GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static V2Form GetInstance(
+            object obj)
+        {
+            if (obj is V2Form)
+            {
+                return (V2Form) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new V2Form((Asn1Sequence) obj);
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+        }
+
+		public V2Form(
+            GeneralNames issuerName)
+        {
+            this.issuerName = issuerName;
+        }
+
+		private V2Form(
+            Asn1Sequence seq)
+        {
+			if (seq.Count > 3)
+			{
+				throw new ArgumentException("Bad sequence size: " + seq.Count);
+			}
+
+			int index = 0;
+
+			if (!(seq[0] is Asn1TaggedObject))
+            {
+                index++;
+                this.issuerName = GeneralNames.GetInstance(seq[0]);
+            }
+
+			for (int i = index; i != seq.Count; i++)
+            {
+				Asn1TaggedObject o = Asn1TaggedObject.GetInstance(seq[i]);
+				if (o.TagNo == 0)
+                {
+                    baseCertificateID = IssuerSerial.GetInstance(o, false);
+                }
+                else if (o.TagNo == 1)
+                {
+                    objectDigestInfo = ObjectDigestInfo.GetInstance(o, false);
+                }
+				else
+				{
+					throw new ArgumentException("Bad tag number: " + o.TagNo);
+				}
+			}
+        }
+
+		public GeneralNames IssuerName
+        {
+            get { return issuerName; }
+        }
+
+		public IssuerSerial BaseCertificateID
+        {
+            get { return baseCertificateID; }
+        }
+
+		public ObjectDigestInfo ObjectDigestInfo
+        {
+            get { return objectDigestInfo; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  V2Form ::= Sequence {
+         *       issuerName            GeneralNames  OPTIONAL,
+         *       baseCertificateID     [0] IssuerSerial  OPTIONAL,
+         *       objectDigestInfo      [1] ObjectDigestInfo  OPTIONAL
+         *         -- issuerName MUST be present in this profile
+         *         -- baseCertificateID and objectDigestInfo MUST NOT
+         *         -- be present in this profile
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector();
+
+			if (issuerName != null)
+            {
+                v.Add(issuerName);
+            }
+
+			if (baseCertificateID != null)
+            {
+                v.Add(new DerTaggedObject(false, 0, baseCertificateID));
+            }
+
+			if (objectDigestInfo != null)
+            {
+                v.Add(new DerTaggedObject(false, 1, objectDigestInfo));
+            }
+
+			return new DerSequence(v);
+        }
+    }
+}
diff --git a/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
new file mode 100644
index 000000000..e50d3563b
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509CertificateStructure.cs
@@ -0,0 +1,129 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+     * an X509Certificate structure.
+     * <pre>
+     *  Certificate ::= Sequence {
+     *      tbsCertificate          TbsCertificate,
+     *      signatureAlgorithm      AlgorithmIdentifier,
+     *      signature               BIT STRING
+     *  }
+     * </pre>
+     */
+    public class X509CertificateStructure
+        : Asn1Encodable
+    {
+        private readonly TbsCertificateStructure	tbsCert;
+        private readonly AlgorithmIdentifier		sigAlgID;
+        private readonly DerBitString				sig;
+
+		public static X509CertificateStructure GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static X509CertificateStructure GetInstance(
+            object obj)
+        {
+            if (obj is X509CertificateStructure)
+                return (X509CertificateStructure)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;
+		}
+
+		private X509CertificateStructure(
+            Asn1Sequence 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]);
+        }
+
+		public TbsCertificateStructure TbsCertificate
+        {
+			get { return tbsCert; }
+        }
+
+		public int Version
+        {
+            get { return tbsCert.Version; }
+        }
+
+		public DerInteger SerialNumber
+        {
+            get { return tbsCert.SerialNumber; }
+        }
+
+		public X509Name Issuer
+        {
+            get { return tbsCert.Issuer; }
+        }
+
+		public Time StartDate
+        {
+            get { return tbsCert.StartDate; }
+        }
+
+		public Time EndDate
+        {
+            get { return tbsCert.EndDate; }
+        }
+
+		public X509Name Subject
+        {
+            get { return tbsCert.Subject; }
+        }
+
+		public SubjectPublicKeyInfo SubjectPublicKeyInfo
+        {
+            get { return tbsCert.SubjectPublicKeyInfo; }
+        }
+
+		public AlgorithmIdentifier SignatureAlgorithm
+        {
+            get { return sigAlgID; }
+        }
+
+		public DerBitString Signature
+        {
+            get { return sig; }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+			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
new file mode 100644
index 000000000..1896450f5
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509Extensions.cs
@@ -0,0 +1,451 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    public class X509Extensions
+        : Asn1Encodable
+    {
+		/**
+		 * Subject Directory Attributes
+		 */
+		public static readonly DerObjectIdentifier SubjectDirectoryAttributes = new DerObjectIdentifier("2.5.29.9");
+
+		/**
+         * Subject Key Identifier
+         */
+        public static readonly DerObjectIdentifier SubjectKeyIdentifier = new DerObjectIdentifier("2.5.29.14");
+
+		/**
+         * Key Usage
+         */
+        public static readonly DerObjectIdentifier KeyUsage = new DerObjectIdentifier("2.5.29.15");
+
+		/**
+         * Private Key Usage Period
+         */
+        public static readonly DerObjectIdentifier PrivateKeyUsagePeriod = new DerObjectIdentifier("2.5.29.16");
+
+		/**
+         * Subject Alternative Name
+         */
+        public static readonly DerObjectIdentifier SubjectAlternativeName = new DerObjectIdentifier("2.5.29.17");
+
+		/**
+         * Issuer Alternative Name
+         */
+        public static readonly DerObjectIdentifier IssuerAlternativeName = new DerObjectIdentifier("2.5.29.18");
+
+		/**
+         * Basic Constraints
+         */
+        public static readonly DerObjectIdentifier BasicConstraints = new DerObjectIdentifier("2.5.29.19");
+
+		/**
+         * CRL Number
+         */
+        public static readonly DerObjectIdentifier CrlNumber = new DerObjectIdentifier("2.5.29.20");
+
+		/**
+         * Reason code
+         */
+        public static readonly DerObjectIdentifier ReasonCode = new DerObjectIdentifier("2.5.29.21");
+
+		/**
+         * Hold Instruction Code
+         */
+        public static readonly DerObjectIdentifier InstructionCode = new DerObjectIdentifier("2.5.29.23");
+
+		/**
+         * Invalidity Date
+         */
+        public static readonly DerObjectIdentifier InvalidityDate = new DerObjectIdentifier("2.5.29.24");
+
+		/**
+         * Delta CRL indicator
+         */
+        public static readonly DerObjectIdentifier DeltaCrlIndicator = new DerObjectIdentifier("2.5.29.27");
+
+		/**
+         * Issuing Distribution Point
+         */
+        public static readonly DerObjectIdentifier IssuingDistributionPoint = new DerObjectIdentifier("2.5.29.28");
+
+		/**
+         * Certificate Issuer
+         */
+        public static readonly DerObjectIdentifier CertificateIssuer = new DerObjectIdentifier("2.5.29.29");
+
+		/**
+         * Name Constraints
+         */
+        public static readonly DerObjectIdentifier NameConstraints = new DerObjectIdentifier("2.5.29.30");
+
+		/**
+         * CRL Distribution Points
+         */
+        public static readonly DerObjectIdentifier CrlDistributionPoints = new DerObjectIdentifier("2.5.29.31");
+
+		/**
+         * Certificate Policies
+         */
+        public static readonly DerObjectIdentifier CertificatePolicies = new DerObjectIdentifier("2.5.29.32");
+
+		/**
+         * Policy Mappings
+         */
+        public static readonly DerObjectIdentifier PolicyMappings = new DerObjectIdentifier("2.5.29.33");
+
+		/**
+         * Authority Key Identifier
+         */
+        public static readonly DerObjectIdentifier AuthorityKeyIdentifier = new DerObjectIdentifier("2.5.29.35");
+
+		/**
+         * Policy Constraints
+         */
+        public static readonly DerObjectIdentifier PolicyConstraints = new DerObjectIdentifier("2.5.29.36");
+
+		/**
+         * Extended Key Usage
+         */
+        public static readonly DerObjectIdentifier ExtendedKeyUsage = new DerObjectIdentifier("2.5.29.37");
+
+		/**
+		 * Freshest CRL
+		 */
+		public static readonly DerObjectIdentifier FreshestCrl = new DerObjectIdentifier("2.5.29.46");
+
+		/**
+         * Inhibit Any Policy
+         */
+        public static readonly DerObjectIdentifier InhibitAnyPolicy = new DerObjectIdentifier("2.5.29.54");
+
+		/**
+         * Authority Info Access
+         */
+		public static readonly DerObjectIdentifier AuthorityInfoAccess = new DerObjectIdentifier("1.3.6.1.5.5.7.1.1");
+
+		/**
+		 * Subject Info Access
+		 */
+		public static readonly DerObjectIdentifier SubjectInfoAccess = new DerObjectIdentifier("1.3.6.1.5.5.7.1.11");
+
+		/**
+		 * Logo Type
+		 */
+		public static readonly DerObjectIdentifier LogoType = new DerObjectIdentifier("1.3.6.1.5.5.7.1.12");
+
+		/**
+		 * BiometricInfo
+		 */
+		public static readonly DerObjectIdentifier BiometricInfo = new DerObjectIdentifier("1.3.6.1.5.5.7.1.2");
+
+		/**
+		 * QCStatements
+		 */
+		public static readonly DerObjectIdentifier QCStatements = new DerObjectIdentifier("1.3.6.1.5.5.7.1.3");
+
+		/**
+		 * Audit identity extension in attribute certificates.
+		 */
+		public static readonly DerObjectIdentifier AuditIdentity = new DerObjectIdentifier("1.3.6.1.5.5.7.1.4");
+
+		/**
+		 * NoRevAvail extension in attribute certificates.
+		 */
+		public static readonly DerObjectIdentifier NoRevAvail = new DerObjectIdentifier("2.5.29.56");
+
+		/**
+		 * TargetInformation extension in attribute certificates.
+		 */
+		public static readonly DerObjectIdentifier TargetInformation = new DerObjectIdentifier("2.5.29.55");
+
+        private readonly IDictionary extensions = Platform.CreateHashtable();
+        private readonly IList ordering;
+
+		public static X509Extensions GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static X509Extensions GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is X509Extensions)
+            {
+                return (X509Extensions) obj;
+            }
+
+			if (obj is Asn1Sequence)
+            {
+                return new X509Extensions((Asn1Sequence) obj);
+            }
+
+			if (obj is Asn1TaggedObject)
+            {
+                return GetInstance(((Asn1TaggedObject) obj).GetObject());
+            }
+
+			throw new ArgumentException("unknown object in factory: " + obj.GetType().Name, "obj");
+		}
+
+		/**
+         * Constructor from Asn1Sequence.
+         *
+         * the extensions are a list of constructed sequences, either with (Oid, OctetString) or (Oid, Boolean, OctetString)
+         */
+        private X509Extensions(
+            Asn1Sequence seq)
+        {
+            this.ordering = Platform.CreateArrayList();
+
+			foreach (Asn1Encodable ae in seq)
+			{
+				Asn1Sequence s = Asn1Sequence.GetInstance(ae.ToAsn1Object());
+
+				if (s.Count < 2 || s.Count > 3)
+					throw new ArgumentException("Bad sequence size: " + s.Count);
+
+				DerObjectIdentifier oid = DerObjectIdentifier.GetInstance(s[0].ToAsn1Object());
+
+				bool isCritical = s.Count == 3
+					&& DerBoolean.GetInstance(s[1].ToAsn1Object()).IsTrue;
+
+				Asn1OctetString octets = Asn1OctetString.GetInstance(s[s.Count - 1].ToAsn1Object());
+
+				extensions.Add(oid, new X509Extension(isCritical, octets));
+				ordering.Add(oid);
+			}
+        }
+
+        /**
+         * constructor from a table of extensions.
+         * <p>
+         * it's is assumed the table contains Oid/string pairs.</p>
+         */
+        public X509Extensions(
+            IDictionary extensions)
+            : this(null, extensions)
+        {
+        }
+
+        /**
+         * Constructor from a table of extensions with ordering.
+         * <p>
+         * It's is assumed the table contains Oid/string pairs.</p>
+         */
+        public X509Extensions(
+            IList       ordering,
+            IDictionary extensions)
+        {
+            if (ordering == null)
+            {
+                this.ordering = Platform.CreateArrayList(extensions.Keys);
+            }
+            else
+            {
+                this.ordering = Platform.CreateArrayList(ordering);
+            }
+
+            foreach (DerObjectIdentifier oid in this.ordering)
+            {
+                this.extensions.Add(oid, (X509Extension)extensions[oid]);
+            }
+        }
+
+        /**
+         * Constructor from two vectors
+         *
+         * @param objectIDs an ArrayList of the object identifiers.
+         * @param values an ArrayList of the extension values.
+         */
+        public X509Extensions(
+            IList oids,
+            IList values)
+        {
+            this.ordering = Platform.CreateArrayList(oids);
+
+            int count = 0;
+            foreach (DerObjectIdentifier oid in this.ordering)
+            {
+                this.extensions.Add(oid, (X509Extension)values[count++]);
+            }
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+		/**
+         * constructor from a table of extensions.
+         * <p>
+         * it's is assumed the table contains Oid/string pairs.</p>
+         */
+        [Obsolete]
+        public X509Extensions(
+            Hashtable extensions)
+             : this(null, extensions)
+        {
+        }
+
+		/**
+         * Constructor from a table of extensions with ordering.
+         * <p>
+         * It's is assumed the table contains Oid/string pairs.</p>
+         */
+        [Obsolete]
+        public X509Extensions(
+            ArrayList	ordering,
+            Hashtable	extensions)
+        {
+            if (ordering == null)
+            {
+                this.ordering = Platform.CreateArrayList(extensions.Keys);
+            }
+            else
+            {
+                this.ordering = Platform.CreateArrayList(ordering);
+            }
+
+            foreach (DerObjectIdentifier oid in this.ordering)
+			{
+				this.extensions.Add(oid, (X509Extension) extensions[oid]);
+			}
+        }
+
+		/**
+		 * Constructor from two vectors
+		 *
+		 * @param objectIDs an ArrayList of the object identifiers.
+		 * @param values an ArrayList of the extension values.
+		 */
+        [Obsolete]
+		public X509Extensions(
+			ArrayList	oids,
+			ArrayList	values)
+		{
+            this.ordering = Platform.CreateArrayList(oids);
+
+            int count = 0;
+			foreach (DerObjectIdentifier oid in this.ordering)
+			{
+				this.extensions.Add(oid, (X509Extension) values[count++]);
+			}
+		}
+#endif
+
+        [Obsolete("Use ExtensionOids IEnumerable property")]
+		public IEnumerator Oids()
+		{
+			return ExtensionOids.GetEnumerator();
+		}
+
+		/**
+		 * return an Enumeration of the extension field's object ids.
+		 */
+		public IEnumerable ExtensionOids
+        {
+			get { return new EnumerableProxy(ordering); }
+        }
+
+		/**
+         * return the extension represented by the object identifier
+         * passed in.
+         *
+         * @return the extension if it's present, null otherwise.
+         */
+        public X509Extension GetExtension(
+            DerObjectIdentifier oid)
+        {
+             return (X509Extension) extensions[oid];
+        }
+
+		/**
+		 * <pre>
+		 *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
+		 *
+		 *     Extension         ::=   SEQUENCE {
+		 *        extnId            EXTENSION.&amp;id ({ExtensionSet}),
+		 *        critical          BOOLEAN DEFAULT FALSE,
+		 *        extnValue         OCTET STRING }
+		 * </pre>
+		 */
+		public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector	vec = new Asn1EncodableVector();
+
+			foreach (DerObjectIdentifier oid in ordering)
+			{
+                X509Extension ext = (X509Extension) extensions[oid];
+                Asn1EncodableVector	v = new Asn1EncodableVector(oid);
+
+				if (ext.IsCritical)
+                {
+                    v.Add(DerBoolean.True);
+                }
+
+				v.Add(ext.Value);
+
+				vec.Add(new DerSequence(v));
+            }
+
+			return new DerSequence(vec);
+        }
+
+		public bool Equivalent(
+			X509Extensions other)
+		{
+			if (extensions.Count != other.extensions.Count)
+				return false;
+
+			foreach (DerObjectIdentifier oid in extensions.Keys)
+			{
+				if (!extensions[oid].Equals(other.extensions[oid]))
+					return false;
+			}
+
+			return true;
+		}
+
+		public DerObjectIdentifier[] GetExtensionOids()
+		{
+			return ToOidArray(ordering);
+		}
+
+		public DerObjectIdentifier[] GetNonCriticalExtensionOids()
+		{
+			return GetExtensionOids(false);
+		}
+
+		public DerObjectIdentifier[] GetCriticalExtensionOids()
+		{
+			return GetExtensionOids(true);
+		}
+
+		private DerObjectIdentifier[] GetExtensionOids(bool isCritical)
+		{
+			IList oids = Platform.CreateArrayList();
+
+			foreach (DerObjectIdentifier oid in this.ordering)
+            {
+				X509Extension ext = (X509Extension)extensions[oid];
+				if (ext.IsCritical == isCritical)
+				{
+					oids.Add(oid);
+				}
+            }
+
+			return ToOidArray(oids);
+		}
+
+		private static DerObjectIdentifier[] ToOidArray(IList oids)
+		{
+			DerObjectIdentifier[] oidArray = new DerObjectIdentifier[oids.Count];
+			oids.CopyTo(oidArray, 0);
+			return oidArray;
+		}
+	}
+}
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
new file mode 100644
index 000000000..b459cbe1b
--- /dev/null
+++ b/Crypto/src/asn1/x509/X509Name.cs
@@ -0,0 +1,1189 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+#if (SILVERLIGHT || PORTABLE)
+using System.Collections.Generic;
+#endif
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Asn1.X509
+{
+    /**
+    * <pre>
+    *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+    *
+    *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
+    *
+    *     AttributeTypeAndValue ::= SEQUENCE {
+    *                                   type  OBJECT IDENTIFIER,
+    *                                   value ANY }
+    * </pre>
+    */
+    public class X509Name
+        : Asn1Encodable
+    {
+        /**
+        * country code - StringType(SIZE(2))
+        */
+        public static readonly DerObjectIdentifier C = new DerObjectIdentifier("2.5.4.6");
+
+        /**
+        * organization - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier O = new DerObjectIdentifier("2.5.4.10");
+
+        /**
+        * organizational unit name - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier OU = new DerObjectIdentifier("2.5.4.11");
+
+        /**
+        * Title
+        */
+        public static readonly DerObjectIdentifier T = new DerObjectIdentifier("2.5.4.12");
+
+        /**
+        * common name - StringType(SIZE(1..64))
+        */
+        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");
+
+		/**
+		* 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");
+
+        /**
+        * state, or province name - StringType(SIZE(1..64))
+        */
+        public static readonly DerObjectIdentifier ST = new DerObjectIdentifier("2.5.4.8");
+
+        /**
+        * Naming attributes of type X520name
+        */
+        public static readonly DerObjectIdentifier Surname = new DerObjectIdentifier("2.5.4.4");
+        public static readonly DerObjectIdentifier GivenName = new DerObjectIdentifier("2.5.4.42");
+        public static readonly DerObjectIdentifier Initials = new DerObjectIdentifier("2.5.4.43");
+        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;
+
+		/**
+        * 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>
+        */
+        public static readonly DerObjectIdentifier EmailAddress = PkcsObjectIdentifiers.Pkcs9AtEmailAddress;
+
+        /**
+        * more from PKCS#9
+        */
+        public static readonly DerObjectIdentifier UnstructuredName = PkcsObjectIdentifiers.Pkcs9AtUnstructuredName;
+        public static readonly DerObjectIdentifier UnstructuredAddress = PkcsObjectIdentifiers.Pkcs9AtUnstructuredAddress;
+
+        /**
+        * email address in Verisign certificates
+        */
+        public static readonly DerObjectIdentifier E = EmailAddress;
+
+        /*
+        * others...
+        */
+        public static readonly DerObjectIdentifier DC = new DerObjectIdentifier("0.9.2342.19200300.100.1.25");
+
+        /**
+        * LDAP User id.
+        */
+        public static readonly DerObjectIdentifier UID = new DerObjectIdentifier("0.9.2342.19200300.100.1.1");
+
+        /**
+        * determines whether or not strings should be processed and printed
+        * from back to front.
+        */
+//        public static bool DefaultReverse = false;
+		public static bool DefaultReverse
+		{
+			get { return defaultReverse[0]; }
+			set { defaultReverse[0] = value; }
+		}
+
+		private static readonly bool[] defaultReverse = { false };
+
+#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 common symbols into their OIDS.
+        */
+        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();
+
+        /**
+        * look up table translating common symbols into their OIDS.
+        */
+        public static readonly Hashtable DefaultLookup = new Hashtable();
+#endif
+
+        static X509Name()
+        {
+            DefaultSymbols.Add(C, "C");
+            DefaultSymbols.Add(O, "O");
+            DefaultSymbols.Add(T, "T");
+            DefaultSymbols.Add(OU, "OU");
+            DefaultSymbols.Add(CN, "CN");
+            DefaultSymbols.Add(L, "L");
+            DefaultSymbols.Add(ST, "ST");
+            DefaultSymbols.Add(SerialNumber, "SERIALNUMBER");
+            DefaultSymbols.Add(EmailAddress, "E");
+            DefaultSymbols.Add(DC, "DC");
+            DefaultSymbols.Add(UID, "UID");
+			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");
+
+            RFC2253Symbols.Add(C, "C");
+            RFC2253Symbols.Add(O, "O");
+            RFC2253Symbols.Add(OU, "OU");
+            RFC2253Symbols.Add(CN, "CN");
+            RFC2253Symbols.Add(L, "L");
+            RFC2253Symbols.Add(ST, "ST");
+			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");
+
+			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("dc", DC);
+            DefaultLookup.Add("e", E);
+            DefaultLookup.Add("uid", UID);
+            DefaultLookup.Add("surname", Surname);
+            DefaultLookup.Add("givenname", GivenName);
+            DefaultLookup.Add("initials", Initials);
+            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);
+		}
+
+        private readonly IList ordering = Platform.CreateArrayList();
+		private readonly X509NameEntryConverter converter;
+
+		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.
+        * @param explicitly true if explicitly tagged false otherwise.
+        * @return the X509Name
+        */
+        public static X509Name GetInstance(
+            Asn1TaggedObject	obj,
+            bool				explicitly)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+        }
+
+		public static X509Name GetInstance(
+            object obj)
+        {
+            if (obj == null || obj is X509Name)
+                return (X509Name)obj;
+
+			if (obj != null)
+				return new X509Name(Asn1Sequence.GetInstance(obj));
+
+			throw new ArgumentException("null object in factory", "obj");
+        }
+
+		protected X509Name()
+		{
+		}
+
+		/**
+        * Constructor from Asn1Sequence
+        *
+        * the principal will be a list of constructed sets, each containing an (OID, string) pair.
+        */
+        protected X509Name(
+            Asn1Sequence seq)
+        {
+            this.seq = seq;
+
+			foreach (Asn1Encodable asn1Obj in seq)
+			{
+				Asn1Set asn1Set = Asn1Set.GetInstance(asn1Obj.ToAsn1Object());
+
+				for (int i = 0; i < asn1Set.Count; i++)
+                {
+					Asn1Sequence s = Asn1Sequence.GetInstance(asn1Set[i].ToAsn1Object());
+
+					if (s.Count != 2)
+						throw new ArgumentException("badly sized pair");
+
+					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;
+						}
+
+						values.Add(v);
+					}
+                    else
+                    {
+						values.Add("#" + Hex.ToHexString(derValue.GetEncoded()));
+                    }
+
+					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>
+        * it's is assumed the table contains OID/string pairs, and the contents
+        * of the table are copied into an internal table as part of the
+        * construction process. The ordering ArrayList should contain the OIDs
+        * in the order they are meant to be encoded or printed in ToString.</p>
+        */
+        public X509Name(
+            IList       ordering,
+            IDictionary attributes)
+            : this(ordering, attributes, new X509DefaultEntryConverter())
+        {
+        }
+
+#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>
+        * it's is assumed the table contains OID/string pairs, and the contents
+        * of the table are copied into an internal table as part of the
+        * construction process. The ordering ArrayList should contain the OIDs
+        * in the order they are meant to be encoded or printed in ToString.</p>
+        * <p>
+        * The passed in converter will be used to convert the strings into their
+        * ASN.1 counterparts.</p>
+        */
+        public X509Name(
+            IList                   ordering,
+            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
+			}
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public X509Name(
+            ArrayList oids,
+            ArrayList values)
+            : this(oids, values, new X509DefaultEntryConverter())
+        {
+        }
+#endif
+
+        /**
+        * Takes two vectors one of the oids and the other of the values.
+        */
+        public X509Name(
+            IList   oids,
+            IList   values)
+            : this(oids, values, new X509DefaultEntryConverter())
+        {
+        }
+
+#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>
+        * The passed in converter will be used to convert the strings into their
+        * ASN.1 counterparts.</p>
+        */
+        public X509Name(
+            IList			    	oids,
+            IList		    		values,
+            X509NameEntryConverter	converter)
+        {
+            this.converter = converter;
+
+			if (oids.Count != values.Count)
+            {
+                throw new ArgumentException("'oids' must be same length as 'values'.");
+            }
+
+			for (int i = 0; i < oids.Count; i++)
+            {
+                this.ordering.Add(oids[i]);
+                this.values.Add(values[i]);
+                this.added.Add(false);
+            }
+        }
+
+//		private static bool IsEncoded(
+//			string s)
+//		{
+//			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.
+        */
+        public X509Name(
+            string dirName)
+            : this(DefaultReverse, (IDictionary)DefaultLookup, dirName)
+        {
+        }
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes with each
+        * string value being converted to its associated ASN.1 type using the passed
+        * in converter.
+        */
+        public X509Name(
+            string					dirName,
+            X509NameEntryConverter	converter)
+            : this(DefaultReverse, DefaultLookup, dirName, converter)
+        {
+        }
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes. If reverse
+        * is true, create the encoded version of the sequence starting from the
+        * last element in the string.
+        */
+        public X509Name(
+            bool	reverse,
+            string	dirName)
+            : this(reverse, (IDictionary)DefaultLookup, dirName)
+        {
+        }
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes with each
+        * string value being converted to its associated ASN.1 type using the passed
+        * in converter. If reverse is true the ASN.1 sequence representing the DN will
+        * be built by starting at the end of the string, rather than the start.
+        */
+        public X509Name(
+            bool					reverse,
+            string					dirName,
+            X509NameEntryConverter	converter)
+            : this(reverse, DefaultLookup, dirName, converter)
+        {
+        }
+
+#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
+        * should provide a table of lookups, indexed by lowercase only strings and
+        * yielding a DerObjectIdentifier, other than that OID. and numeric oids
+        * will be processed automatically.
+        * <br/>
+        * If reverse is true, create the encoded version of the sequence
+        * starting from the last element in the string.
+        * @param reverse true if we should start scanning from the end (RFC 2553).
+        * @param lookUp table of names and their oids.
+        * @param dirName the X.500 string to be parsed.
+        */
+        public X509Name(
+            bool		reverse,
+            IDictionary lookUp,
+            string		dirName)
+            : this(reverse, lookUp, dirName, new X509DefaultEntryConverter())
+        {
+        }
+
+		private DerObjectIdentifier DecodeOid(
+            string		name,
+            IDictionary lookUp)
+        {
+            if (name.ToUpperInvariant().StartsWith("OID."))
+            {
+                return new DerObjectIdentifier(name.Substring(4));
+            }
+            else if (name[0] >= '0' && name[0] <= '9')
+            {
+                return new DerObjectIdentifier(name);
+            }
+
+			DerObjectIdentifier oid = (DerObjectIdentifier)lookUp[name.ToLowerInvariant()];
+            if (oid == null)
+            {
+                throw new ArgumentException("Unknown object id - " + name + " - passed to distinguished name");
+            }
+
+			return oid;
+        }
+
+		/**
+        * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+        * some such, converting it into an ordered set of name attributes. lookUp
+        * should provide a table of lookups, indexed by lowercase only strings and
+        * yielding a DerObjectIdentifier, other than that OID. and numeric oids
+        * will be processed automatically. The passed in converter is used to convert the
+        * string values to the right of each equals sign to their ASN.1 counterparts.
+        * <br/>
+        * @param reverse true if we should start scanning from the end, false otherwise.
+        * @param lookUp table of names and oids.
+        * @param dirName the string dirName
+        * @param converter the converter to convert string values into their ASN.1 equivalents
+        */
+        public X509Name(
+            bool					reverse,
+            IDictionary				lookUp,
+            string					dirName,
+            X509NameEntryConverter	converter)
+        {
+            this.converter = converter;
+            X509NameTokenizer nTok = new X509NameTokenizer(dirName);
+
+			while (nTok.HasMoreTokens())
+            {
+                string token = nTok.NextToken();
+                int index = token.IndexOf('=');
+
+				if (index == -1)
+                {
+                    throw new ArgumentException("badly formated directory string");
+                }
+
+				string name = token.Substring(0, index);
+                string value = token.Substring(index + 1);
+                DerObjectIdentifier	oid = DecodeOid(name, lookUp);
+
+				if (value.IndexOf('+') > 0)
+                {
+                    X509NameTokenizer vTok = new X509NameTokenizer(value, '+');
+					string v = vTok.NextToken();
+
+					this.ordering.Add(oid);
+                    this.values.Add(v);
+                    this.added.Add(false);
+
+					while (vTok.HasMoreTokens())
+                    {
+                        string sv = vTok.NextToken();
+                        int ndx = sv.IndexOf('=');
+
+                        string nm = sv.Substring(0, ndx);
+                        string vl = sv.Substring(ndx + 1);
+                        this.ordering.Add(DecodeOid(nm, lookUp));
+                        this.values.Add(vl);
+                        this.added.Add(true);
+                    }
+                }
+                else
+                {
+                    this.ordering.Add(oid);
+                    this.values.Add(value);
+                    this.added.Add(false);
+                }
+            }
+
+			if (reverse)
+            {
+//				this.ordering.Reverse();
+//				this.values.Reverse();
+//				this.added.Reverse();
+				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;
+			}
+        }
+
+#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);
+        }
+#endif
+
+        /**
+        * return an IList of the oids in the name, in the order they were found.
+        */
+        public IList GetOidList()
+        {
+            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);
+        }
+
+#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.
+		 */
+        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))
+                {
+                    string val = (string)values[i];
+
+                    if (val.StartsWith("\\#"))
+                    {
+                        val = val.Substring(1);
+                    }
+
+                    v.Add(val);
+                }
+            }
+        }
+
+		public override Asn1Object ToAsn1Object()
+        {
+            if (seq == null)
+            {
+                Asn1EncodableVector vec = new Asn1EncodableVector();
+                Asn1EncodableVector sVec = new Asn1EncodableVector();
+                DerObjectIdentifier lstOid = null;
+
+				for (int i = 0; i != ordering.Count; i++)
+                {
+                    DerObjectIdentifier oid = (DerObjectIdentifier)ordering[i];
+					string str = (string)values[i];
+
+					if (lstOid == null
+                        || ((bool)this.added[i]))
+                    {
+                    }
+                    else
+                    {
+                        vec.Add(new DerSet(sVec));
+                        sVec = new Asn1EncodableVector();
+                    }
+
+					sVec.Add(
+						new DerSequence(
+							oid,
+							converter.GetConvertedValue(oid, str)));
+
+					lstOid = oid;
+                }
+
+				vec.Add(new DerSet(sVec));
+
+				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);
+
+			if (other == null)
+				return false;
+
+			if (other == this)
+				return true;
+
+			int orderingSize = ordering.Count;
+
+			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];
+
+				if (!oid.Equals(oOid))
+					return false;
+
+				string val = (string) values[i];
+				string oVal = (string) other.values[i];
+
+				if (!equivalentStrings(val, oVal))
+					return false;
+			}
+
+			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(
+            StringBuilder		buf,
+            IDictionary         oidSymbols,
+            DerObjectIdentifier	oid,
+            string				val)
+        {
+            string sym = (string)oidSymbols[oid];
+
+            if (sym != null)
+            {
+                buf.Append(sym);
+            }
+            else
+            {
+                buf.Append(oid.Id);
+            }
+
+            buf.Append('=');
+
+            int index = buf.Length;
+
+            buf.Append(val);
+
+            int end = buf.Length;
+
+			if (val.StartsWith("\\#"))
+			{
+				index += 2;
+			}
+
+			while (index != end)
+            {
+                if ((buf[index] == ',')
+                || (buf[index] == '"')
+                || (buf[index] == '\\')
+                || (buf[index] == '+')
+				|| (buf[index] == '=')
+                || (buf[index] == '<')
+                || (buf[index] == '>')
+                || (buf[index] == ';'))
+                {
+                    buf.Insert(index++, "\\");
+                    end++;
+                }
+
+                index++;
+            }
+        }
+
+#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
+        * in the sequence (ala RFC 2253), otherwise the string will begin
+        * with the first element of the structure. If no string definition
+        * for the oid is found in oidSymbols the string value of the oid is
+        * added. Two standard symbol tables are provided DefaultSymbols, and
+        * RFC2253Symbols as part of this class.
+        *
+        * @param reverse if true start at the end of the sequence and work back.
+        * @param oidSymbols look up table strings for oids.
+        */
+        public string ToString(
+            bool		reverse,
+            IDictionary oidSymbols)
+        {
+#if (SILVERLIGHT || PORTABLE)
+            List<object> components = new List<object>();
+#else
+			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()
+        {
+            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/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
new file mode 100644
index 000000000..de80ca280
--- /dev/null
+++ b/Crypto/src/asn1/x9/X962NamedCurves.cs
@@ -0,0 +1,733 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+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();
+        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); }
+		}
+	}
+}
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
new file mode 100644
index 000000000..b92e7b3b5
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9Curve.cs
@@ -0,0 +1,147 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * ASN.1 def for Elliptic-Curve Curve structure. See
+     * X9.62, for further details.
+     */
+    public class X9Curve
+        : Asn1Encodable
+    {
+        private readonly ECCurve curve;
+        private readonly byte[] seed;
+		private readonly DerObjectIdentifier fieldIdentifier;
+
+		public X9Curve(
+            ECCurve curve)
+			: this(curve, null)
+        {
+            this.curve = curve;
+        }
+
+		public X9Curve(
+            ECCurve	curve,
+            byte[]	seed)
+        {
+			if (curve == null)
+				throw new ArgumentNullException("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(
+            X9FieldID		fieldID,
+            Asn1Sequence	seq)
+        {
+			if (fieldID == null)
+				throw new ArgumentNullException("fieldID");
+			if (seq == null)
+				throw new ArgumentNullException("seq");
+
+			this.fieldIdentifier = fieldID.Identifier;
+
+			if (fieldIdentifier.Equals(X9ObjectIdentifiers.PrimeField))
+            {
+                BigInteger q = ((DerInteger) fieldID.Parameters).Value;
+                X9FieldElement x9A = new X9FieldElement(q, (Asn1OctetString) seq[0]);
+                X9FieldElement x9B = new X9FieldElement(q, (Asn1OctetString) seq[1]);
+                curve = new FpCurve(q, x9A.Value.ToBigInteger(), x9B.Value.ToBigInteger());
+            }
+            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)
+            {
+                seed = ((DerBitString) seq[2]).GetBytes();
+            }
+        }
+
+		public ECCurve Curve
+        {
+			get { return curve; }
+        }
+
+		public byte[] GetSeed()
+        {
+            return Arrays.Clone(seed);
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  Curve ::= Sequence {
+         *      a               FieldElement,
+         *      b               FieldElement,
+         *      seed            BIT STRING      OPTIONAL
+         *  }
+         * </pre>
+         */
+        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);
+		}
+    }
+}
diff --git a/Crypto/src/asn1/x9/X9ECParameters.cs b/Crypto/src/asn1/x9/X9ECParameters.cs
new file mode 100644
index 000000000..d025b36ce
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9ECParameters.cs
@@ -0,0 +1,170 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * ASN.1 def for Elliptic-Curve ECParameters structure. See
+     * X9.62, for further details.
+     */
+    public class X9ECParameters
+        : Asn1Encodable
+    {
+        private X9FieldID	fieldID;
+        private ECCurve		curve;
+        private ECPoint		g;
+        private BigInteger	n;
+        private BigInteger	h;
+        private byte[]		seed;
+
+		public X9ECParameters(
+            Asn1Sequence seq)
+        {
+            if (!(seq[0] is DerInteger)
+               || !((DerInteger) seq[0]).Value.Equals(BigInteger.One))
+            {
+                throw new ArgumentException("bad version in X9ECParameters");
+            }
+
+			X9Curve x9c = null;
+            if (seq[2] is X9Curve)
+            {
+                x9c = (X9Curve) seq[2];
+            }
+            else
+            {
+                x9c = new X9Curve(
+					new X9FieldID(
+						(Asn1Sequence) seq[1]),
+						(Asn1Sequence) seq[2]);
+            }
+
+			this.curve = x9c.Curve;
+
+			if (seq[3] is X9ECPoint)
+            {
+                this.g = ((X9ECPoint) seq[3]).Point;
+            }
+            else
+            {
+                this.g = new X9ECPoint(curve, (Asn1OctetString) seq[3]).Point;
+            }
+
+			this.n = ((DerInteger) seq[4]).Value;
+            this.seed = x9c.GetSeed();
+
+			if (seq.Count == 6)
+            {
+                this.h = ((DerInteger) seq[5]).Value;
+            }
+        }
+
+		public X9ECParameters(
+            ECCurve		curve,
+            ECPoint		g,
+            BigInteger	n)
+            : this(curve, g, n, BigInteger.One, null)
+        {
+        }
+
+		public X9ECParameters(
+            ECCurve		curve,
+            ECPoint		g,
+            BigInteger	n,
+            BigInteger	h)
+            : this(curve, g, n, h, null)
+        {
+        }
+
+		public X9ECParameters(
+            ECCurve		curve,
+            ECPoint		g,
+            BigInteger	n,
+            BigInteger	h,
+            byte[]		seed)
+        {
+            this.curve = curve;
+            this.g = g;
+            this.n = n;
+            this.h = h;
+            this.seed = seed;
+
+			if (curve 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);
+			}
+        }
+
+		public ECCurve Curve
+        {
+			get { return curve; }
+        }
+
+		public ECPoint G
+        {
+            get { return g; }
+        }
+
+		public BigInteger N
+        {
+            get { return n; }
+        }
+
+		public BigInteger H
+        {
+            get
+			{
+				if (h == null)
+				{
+					// TODO - this should be calculated, it will cause issues with custom curves.
+					return BigInteger.One;
+				}
+
+				return h;
+			}
+        }
+
+		public byte[] GetSeed()
+        {
+            return seed;
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  ECParameters ::= Sequence {
+         *      version         Integer { ecpVer1(1) } (ecpVer1),
+         *      fieldID         FieldID {{FieldTypes}},
+         *      curve           X9Curve,
+         *      base            X9ECPoint,
+         *      order           Integer,
+         *      cofactor        Integer OPTIONAL
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(
+				new DerInteger(1),
+				fieldID,
+				new X9Curve(curve, seed),
+				new X9ECPoint(g),
+				new DerInteger(n));
+
+			if (h != null)
+            {
+                v.Add(new DerInteger(h));
+            }
+
+			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
new file mode 100644
index 000000000..ba2b2bcbf
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9ECPoint.cs
@@ -0,0 +1,44 @@
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * class for describing an ECPoint as a Der object.
+     */
+    public class X9ECPoint
+        : Asn1Encodable
+    {
+        private readonly ECPoint p;
+
+		public X9ECPoint(
+            ECPoint p)
+        {
+            this.p = p;
+        }
+
+		public X9ECPoint(
+            ECCurve			c,
+            Asn1OctetString	s)
+        {
+            this.p = c.DecodePoint(s.GetOctets());
+        }
+
+		public ECPoint Point
+        {
+			get { return p; }
+        }
+
+		/**
+         * Produce an object suitable for an Asn1OutputStream.
+         * <pre>
+         *  ECPoint ::= OCTET STRING
+         * </pre>
+         * <p>
+         * Octet string produced using ECPoint.GetEncoded().</p>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerOctetString(p.GetEncoded());
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x9/X9FieldElement.cs b/Crypto/src/asn1/x9/X9FieldElement.cs
new file mode 100644
index 000000000..06fa0e3dc
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9FieldElement.cs
@@ -0,0 +1,69 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * Class for processing an ECFieldElement as a DER object.
+     */
+    public class X9FieldElement
+        : Asn1Encodable
+    {
+		private ECFieldElement 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(
+			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
+        {
+            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);
+
+			return new DerOctetString(paddedBigInteger);
+		}
+    }
+}
diff --git a/Crypto/src/asn1/x9/X9FieldID.cs b/Crypto/src/asn1/x9/X9FieldID.cs
new file mode 100644
index 000000000..c51cc4df2
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9FieldID.cs
@@ -0,0 +1,102 @@
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    /**
+     * ASN.1 def for Elliptic-Curve Field ID structure. See
+     * X9.62, for further details.
+     */
+    public class X9FieldID
+        : Asn1Encodable
+    {
+        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 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)));
+			}
+
+			this.parameters = new DerSequence(fieldIdParams);
+		}
+
+		internal X9FieldID(
+			Asn1Sequence seq)
+		{
+			this.id = (DerObjectIdentifier) seq[0];
+			this.parameters = (Asn1Object) seq[1];
+		}
+
+		public DerObjectIdentifier Identifier
+        {
+            get { return id; }
+        }
+
+		public Asn1Object Parameters
+        {
+            get { return parameters; }
+        }
+
+		/**
+         * Produce a Der encoding of the following structure.
+         * <pre>
+         *  FieldID ::= Sequence {
+         *      fieldType       FIELD-ID.&amp;id({IOSet}),
+         *      parameters      FIELD-ID.&amp;Type({IOSet}{&#64;fieldType})
+         *  }
+         * </pre>
+         */
+        public override Asn1Object ToAsn1Object()
+        {
+			return new DerSequence(id, parameters);
+        }
+    }
+}
diff --git a/Crypto/src/asn1/x9/X9IntegerConverter.cs b/Crypto/src/asn1/x9/X9IntegerConverter.cs
new file mode 100644
index 000000000..2bce20488
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9IntegerConverter.cs
@@ -0,0 +1,48 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Asn1.X9
+{
+    public sealed class X9IntegerConverter
+    {
+		private X9IntegerConverter()
+		{
+		}
+
+		public static int GetByteLength(
+            ECFieldElement fe)
+        {
+			return (fe.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();
+
+			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;
+		}
+    }
+}
diff --git a/Crypto/src/asn1/x9/X9ObjectIdentifiers.cs b/Crypto/src/asn1/x9/X9ObjectIdentifiers.cs
new file mode 100644
index 000000000..5b2fdbd2d
--- /dev/null
+++ b/Crypto/src/asn1/x9/X9ObjectIdentifiers.cs
@@ -0,0 +1,135 @@
+namespace Org.BouncyCastle.Asn1.X9
+{
+    public abstract class X9ObjectIdentifiers
+    {
+        //
+        // X9.62
+        //
+        // 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 CharacteristicTwoField
+                        = new DerObjectIdentifier(IdFieldType + ".2");
+
+		public static readonly DerObjectIdentifier GNBasis
+                        = new DerObjectIdentifier(IdFieldType + ".2.3.1");
+
+		public static readonly DerObjectIdentifier TPBasis
+                        = new DerObjectIdentifier(IdFieldType + ".2.3.2");
+
+		public static readonly DerObjectIdentifier PPBasis
+                        = new DerObjectIdentifier(IdFieldType + ".2.3.3");
+
+		public const string IdECSigType = AnsiX962 + ".4";
+
+		public static readonly DerObjectIdentifier ECDsaWithSha1
+                        = new DerObjectIdentifier(IdECSigType + ".1");
+
+		public const string IdPublicKeyType = AnsiX962 + ".2";
+
+		public static readonly DerObjectIdentifier IdECPublicKey
+                        = new DerObjectIdentifier(IdPublicKeyType + ".1");
+
+		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");
+
+
+		//
+        // named curves
+        //
+        public static readonly DerObjectIdentifier EllipticCurve = new DerObjectIdentifier(AnsiX962 + ".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");
+
+		//
+        // Prime
+        //
+        public static readonly DerObjectIdentifier PrimeCurve = new DerObjectIdentifier(EllipticCurve + ".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");
+
+		//
+        // 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.42
+		 */
+
+		internal const string AnsiX942 = "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");
+	}
+}
diff --git a/Crypto/src/bcpg/ArmoredInputStream.cs b/Crypto/src/bcpg/ArmoredInputStream.cs
new file mode 100644
index 000000000..0dcc948d3
--- /dev/null
+++ b/Crypto/src/bcpg/ArmoredInputStream.cs
@@ -0,0 +1,517 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    /**
+    * reader for Base64 armored objects - read the headers and then start returning
+    * bytes when the data is reached. An IOException is thrown if the CRC check
+    * fails.
+    */
+    public class ArmoredInputStream
+        : BaseInputStream
+    {
+        /*
+        * set up the decoding table.
+        */
+        private readonly static byte[] decodingTable;
+        static ArmoredInputStream()
+        {
+            decodingTable = new byte[128];
+            for (int i = 'A'; i <= 'Z'; i++)
+            {
+                decodingTable[i] = (byte)(i - 'A');
+            }
+            for (int i = 'a'; i <= 'z'; i++)
+            {
+                decodingTable[i] = (byte)(i - 'a' + 26);
+            }
+            for (int i = '0'; i <= '9'; i++)
+            {
+                decodingTable[i] = (byte)(i - '0' + 52);
+            }
+            decodingTable['+'] = 62;
+            decodingTable['/'] = 63;
+        }
+
+        /**
+        * decode the base 64 encoded input data.
+        *
+        * @return the offset the data starts in out.
+        */
+        private int Decode(
+            int      in0,
+            int      in1,
+            int      in2,
+            int      in3,
+            int[]    result)
+        {
+            if (in3 < 0)
+            {
+                throw new EndOfStreamException("unexpected end of file in armored stream.");
+            }
+
+            int    b1, b2, b3, b4;
+            if (in2 == '=')
+            {
+                b1 = decodingTable[in0] &0xff;
+                b2 = decodingTable[in1] & 0xff;
+                result[2] = ((b1 << 2) | (b2 >> 4)) & 0xff;
+                return 2;
+            }
+            else if (in3 == '=')
+            {
+                b1 = decodingTable[in0];
+                b2 = decodingTable[in1];
+                b3 = decodingTable[in2];
+                result[1] = ((b1 << 2) | (b2 >> 4)) & 0xff;
+                result[2] = ((b2 << 4) | (b3 >> 2)) & 0xff;
+                return 1;
+            }
+            else
+            {
+                b1 = decodingTable[in0];
+                b2 = decodingTable[in1];
+                b3 = decodingTable[in2];
+                b4 = decodingTable[in3];
+                result[0] = ((b1 << 2) | (b2 >> 4)) & 0xff;
+                result[1] = ((b2 << 4) | (b3 >> 2)) & 0xff;
+                result[2] = ((b3 << 6) | b4) & 0xff;
+                return 0;
+            }
+        }
+
+        Stream      input;
+        bool        start = true;
+        int[]       outBuf = new int[3];
+        int         bufPtr = 3;
+        Crc24       crc = new Crc24();
+        bool        crcFound = false;
+        bool        hasHeaders = true;
+        string      header = null;
+        bool        newLineFound = false;
+        bool        clearText = false;
+        bool        restart = false;
+        IList       headerList= Platform.CreateArrayList();
+        int         lastC = 0;
+		bool		isEndOfStream;
+
+        /**
+        * Create a stream for reading a PGP armoured message, parsing up to a header
+        * and then reading the data that follows.
+        *
+        * @param input
+        */
+        public ArmoredInputStream(
+            Stream input)
+			: this(input, true)
+        {
+        }
+
+		/**
+        * Create an armoured input stream which will assume the data starts
+        * straight away, or parse for headers first depending on the value of
+        * hasHeaders.
+        *
+        * @param input
+        * @param hasHeaders true if headers are to be looked for, false otherwise.
+        */
+        public ArmoredInputStream(
+            Stream	input,
+            bool	hasHeaders)
+        {
+            this.input = input;
+            this.hasHeaders = hasHeaders;
+
+			if (hasHeaders)
+            {
+                ParseHeaders();
+            }
+
+			start = false;
+        }
+
+		private bool ParseHeaders()
+        {
+            header = null;
+
+			int		c;
+            int		last = 0;
+            bool	headerFound = false;
+
+            headerList = Platform.CreateArrayList();
+
+			//
+            // if restart we already have a header
+            //
+            if (restart)
+            {
+                headerFound = true;
+            }
+            else
+            {
+                while ((c = input.ReadByte()) >= 0)
+                {
+                    if (c == '-' && (last == 0 || last == '\n' || last == '\r'))
+                    {
+                        headerFound = true;
+                        break;
+                    }
+
+					last = c;
+                }
+            }
+
+			if (headerFound)
+            {
+                StringBuilder    Buffer = new StringBuilder("-");
+                bool             eolReached = false;
+                bool             crLf = false;
+
+				if (restart)    // we've had to look ahead two '-'
+                {
+                    Buffer.Append('-');
+                }
+
+				while ((c = input.ReadByte()) >= 0)
+                {
+                    if (last == '\r' && c == '\n')
+                    {
+                        crLf = true;
+                    }
+                    if (eolReached && (last != '\r' && c == '\n'))
+                    {
+                        break;
+                    }
+                    if (eolReached && c == '\r')
+                    {
+                        break;
+                    }
+                    if (c == '\r' || (last != '\r' && c == '\n'))
+                    {
+						string line = Buffer.ToString();
+						if (line.Trim().Length < 1)
+							break;
+                        headerList.Add(line);
+                        Buffer.Length = 0;
+                    }
+
+                    if (c != '\n' && c != '\r')
+                    {
+                        Buffer.Append((char)c);
+                        eolReached = false;
+                    }
+                    else
+                    {
+                        if (c == '\r' || (last != '\r' && c == '\n'))
+                        {
+                            eolReached = true;
+                        }
+                    }
+
+					last = c;
+                }
+
+				if (crLf)
+                {
+                    input.ReadByte(); // skip last \n
+                }
+            }
+
+			if (headerList.Count > 0)
+            {
+                header = (string) headerList[0];
+            }
+
+			clearText = "-----BEGIN PGP SIGNED MESSAGE-----".Equals(header);
+            newLineFound = true;
+
+			return headerFound;
+        }
+
+		/**
+        * @return true if we are inside the clear text section of a PGP
+        * signed message.
+        */
+        public bool IsClearText()
+        {
+            return clearText;
+        }
+
+		/**
+		 * @return true if the stream is actually at end of file.
+		 */
+		public bool IsEndOfStream()
+		{
+			return isEndOfStream;
+		}
+
+		/**
+        * Return the armor header line (if there is one)
+        * @return the armor header line, null if none present.
+        */
+        public string GetArmorHeaderLine()
+        {
+            return header;
+        }
+
+		/**
+        * Return the armor headers (the lines after the armor header line),
+        * @return an array of armor headers, null if there aren't any.
+        */
+        public string[] GetArmorHeaders()
+        {
+            if (headerList.Count <= 1)
+            {
+                return null;
+            }
+
+			string[] hdrs = new string[headerList.Count - 1];
+            for (int i = 0; i != hdrs.Length; i++)
+            {
+                hdrs[i] = (string) headerList[i + 1];
+            }
+
+			return hdrs;
+        }
+
+		private int ReadIgnoreSpace()
+        {
+            int c;
+            do
+            {
+                c = input.ReadByte();
+            }
+            while (c == ' ' || c == '\t');
+
+			return c;
+        }
+
+		private int ReadIgnoreWhitespace()
+        {
+            int c;
+            do
+            {
+                c = input.ReadByte();
+            }
+            while (c == ' ' || c == '\t' || c == '\r' || c == '\n');
+
+            return c;
+        }
+
+		private int ReadByteClearText()
+        {
+            int c = input.ReadByte();
+
+            if (c == '\r' || (c == '\n' && lastC != '\r'))
+            {
+                newLineFound = true;
+            }
+            else if (newLineFound && c == '-')
+            {
+                c = input.ReadByte();
+                if (c == '-')            // a header, not dash escaped
+                {
+                    clearText = false;
+                    start = true;
+                    restart = true;
+                }
+                else                   // a space - must be a dash escape
+                {
+                    c = input.ReadByte();
+                }
+                newLineFound = false;
+            }
+            else
+            {
+                if (c != '\n' && lastC != '\r')
+                {
+                    newLineFound = false;
+                }
+            }
+
+            lastC = c;
+
+			if (c < 0)
+			{
+				isEndOfStream = true;
+			}
+
+			return c;
+        }
+
+        private int ReadClearText(byte[] buffer, int offset, int count)
+        {
+            int pos = offset;
+            try
+            {
+                int end = offset + count;
+                while (pos < end)
+                {
+                    int c = ReadByteClearText();
+                    if (c == -1)
+                    {
+                        break;
+                    }
+                    buffer[pos++] = (byte) c;
+                }
+            }
+            catch (IOException ioe)
+            {
+                if (pos == offset) throw ioe;
+            }
+
+			return pos - offset;
+        }
+
+        private int DoReadByte()
+        {
+            if (bufPtr > 2 || crcFound)
+            {
+                int c = ReadIgnoreSpace();
+                if (c == '\n' || c == '\r')
+                {
+                    c = ReadIgnoreWhitespace();
+                    if (c == '=')            // crc reached
+                    {
+                        bufPtr = Decode(ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
+
+                        if (bufPtr != 0)
+                        {
+                            throw new IOException("no crc found in armored message.");
+                        }
+
+                        crcFound = true;
+
+                        int i = ((outBuf[0] & 0xff) << 16)
+                            | ((outBuf[1] & 0xff) << 8)
+                            | (outBuf[2] & 0xff);
+
+                        if (i != crc.Value)
+                        {
+                            throw new IOException("crc check failed in armored message.");
+                        }
+
+						return ReadByte();
+                    }
+
+                    if (c == '-')        // end of record reached
+                    {
+                        while ((c = input.ReadByte()) >= 0)
+                        {
+                            if (c == '\n' || c == '\r')
+                            {
+                                break;
+                            }
+                        }
+
+                        if (!crcFound)
+                        {
+                            throw new IOException("crc check not found.");
+                        }
+
+                        crcFound = false;
+                        start = true;
+                        bufPtr = 3;
+
+						if (c < 0)
+						{
+							isEndOfStream = true;
+						}
+
+						return -1;
+                    }
+                }
+
+                if (c < 0)
+                {
+					isEndOfStream = true;
+					return -1;
+                }
+
+                bufPtr = Decode(c, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
+            }
+
+            return outBuf[bufPtr++];
+        }
+
+        public override int ReadByte()
+        {
+            if (start)
+            {
+                if (hasHeaders)
+                {
+                    ParseHeaders();
+                }
+
+				crc.Reset();
+				start = false;
+            }
+
+			if (clearText)
+            {
+                return ReadByteClearText();
+            }
+
+            int c = DoReadByte();
+
+            crc.Update(c);
+
+            return c;
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            if (start && count > 0)
+            {
+                if (hasHeaders)
+                {
+                    ParseHeaders();
+                }
+                start = false;
+            }
+
+            if (clearText)
+            {
+                return ReadClearText(buffer, offset, count);
+            }
+
+            int pos = offset;
+            try
+            {
+                int end = offset + count;
+                while (pos < end)
+                {
+                    int c = DoReadByte();
+                    crc.Update(c);
+                    if (c == -1)
+                    {
+                        break;
+                    }
+                    buffer[pos++] = (byte) c;
+                }
+            }
+            catch (IOException ioe)
+            {
+                if (pos == offset) throw ioe;
+            }
+
+            return pos - offset;
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                input.Dispose();
+            }
+
+            base.Dispose(disposing);
+        }
+    }
+}
diff --git a/Crypto/src/bcpg/ArmoredOutputStream.cs b/Crypto/src/bcpg/ArmoredOutputStream.cs
new file mode 100644
index 000000000..7ee26886a
--- /dev/null
+++ b/Crypto/src/bcpg/ArmoredOutputStream.cs
@@ -0,0 +1,333 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    /**
+    * Basic output stream.
+    */
+    public class ArmoredOutputStream
+        : BaseOutputStream
+    {
+        private static 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)'/'
+        };
+
+        /**
+         * encode the input data producing a base 64 encoded byte array.
+         */
+        private static void Encode(
+            Stream	outStream,
+            int[]	data,
+            int		len)
+        {
+			Debug.Assert(len > 0);
+			Debug.Assert(len < 4);
+
+			byte[] bs = new byte[4];
+			int d1 = data[0];
+			bs[0] = encodingTable[(d1 >> 2) & 0x3f];
+
+			switch (len)
+            {
+				case 1:
+				{
+					bs[1] = encodingTable[(d1 << 4) & 0x3f];
+					bs[2] = (byte)'=';
+					bs[3] = (byte)'=';
+					break;
+				}
+				case 2:
+				{
+					int d2 = data[1];
+					bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
+					bs[2] = encodingTable[(d2 << 2) & 0x3f];
+					bs[3] = (byte)'=';
+					break;
+				}
+				case 3:
+				{
+					int d2 = data[1];
+					int d3 = data[2];
+					bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
+					bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f];
+					bs[3] = encodingTable[d3 & 0x3f];
+					break;
+				}
+            }
+
+			outStream.Write(bs, 0, bs.Length);
+        }
+
+        private readonly Stream outStream;
+        private int[]           buf = new int[3];
+        private int             bufPtr = 0;
+        private Crc24           crc = new Crc24();
+        private int             chunkCount = 0;
+        private int             lastb;
+
+        private bool            start = true;
+        private bool            clearText = false;
+        private bool            newLine = false;
+
+        private string          type;
+
+        private static readonly string	nl = Platform.NewLine;
+        private static readonly string	headerStart = "-----BEGIN PGP ";
+        private static readonly string	headerTail = "-----";
+        private static readonly string	footerStart = "-----END PGP ";
+        private static readonly string	footerTail = "-----";
+
+        private static readonly string version = "BCPG C# v" + AssemblyInfo.Version;
+
+		private readonly IDictionary headers;
+
+		public ArmoredOutputStream(Stream outStream)
+        {
+            this.outStream = outStream;
+            this.headers = Platform.CreateHashtable();
+            this.headers["Version"] = version;
+        }
+
+        public ArmoredOutputStream(Stream outStream, IDictionary headers)
+        {
+            this.outStream = outStream;
+            this.headers = Platform.CreateHashtable(headers);
+            this.headers["Version"] = version;
+        }
+
+        /**
+         * Set an additional header entry.
+         *
+         * @param name the name of the header entry.
+         * @param v the value of the header entry.
+         */
+        public void SetHeader(
+            string name,
+            string v)
+        {
+            headers[name] = v;
+        }
+
+        /**
+         * Reset the headers to only contain a Version string.
+         */
+        public void ResetHeaders()
+        {
+            headers.Clear();
+            headers["Version"] = version;
+        }
+
+        /**
+         * Start a clear text signed message.
+         * @param hashAlgorithm
+         */
+        public void BeginClearText(
+            HashAlgorithmTag    hashAlgorithm)
+        {
+            string    hash;
+
+            switch (hashAlgorithm)
+            {
+            case HashAlgorithmTag.Sha1:
+                hash = "SHA1";
+                break;
+            case HashAlgorithmTag.Sha256:
+                hash = "SHA256";
+                break;
+            case HashAlgorithmTag.Sha384:
+                hash = "SHA384";
+                break;
+            case HashAlgorithmTag.Sha512:
+                hash = "SHA512";
+                break;
+            case HashAlgorithmTag.MD2:
+                hash = "MD2";
+                break;
+            case HashAlgorithmTag.MD5:
+                hash = "MD5";
+                break;
+            case HashAlgorithmTag.RipeMD160:
+                hash = "RIPEMD160";
+                break;
+            default:
+                throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm);
+            }
+
+			DoWrite("-----BEGIN PGP SIGNED MESSAGE-----" + nl);
+            DoWrite("Hash: " + hash + nl + nl);
+
+			clearText = true;
+            newLine = true;
+            lastb = 0;
+        }
+
+        public void EndClearText()
+        {
+            clearText = false;
+        }
+
+        public override void WriteByte(
+            byte b)
+        {
+            if (clearText)
+            {
+                outStream.WriteByte(b);
+
+                if (newLine)
+                {
+                    if (!(b == '\n' && lastb == '\r'))
+                    {
+                        newLine = false;
+                    }
+                    if (b == '-')
+                    {
+                        outStream.WriteByte((byte)' ');
+                        outStream.WriteByte((byte)'-');      // dash escape
+                    }
+                }
+                if (b == '\r' || (b == '\n' && lastb != '\r'))
+                {
+                    newLine = true;
+                }
+                lastb = b;
+                return;
+            }
+
+            if (start)
+            {
+                bool newPacket = (b & 0x40) != 0;
+
+				int tag;
+                if (newPacket)
+                {
+                    tag = b & 0x3f;
+                }
+                else
+                {
+                    tag = (b & 0x3f) >> 2;
+                }
+
+                switch ((PacketTag)tag)
+                {
+                case PacketTag.PublicKey:
+                    type = "PUBLIC KEY BLOCK";
+                    break;
+                case PacketTag.SecretKey:
+                    type = "PRIVATE KEY BLOCK";
+                    break;
+                case PacketTag.Signature:
+                    type = "SIGNATURE";
+                    break;
+                default:
+                    type = "MESSAGE";
+				    break;
+                }
+
+                DoWrite(headerStart + type + headerTail + nl);
+                WriteHeaderEntry("Version", (string) headers["Version"]);
+
+                foreach (DictionaryEntry de in headers)
+                {
+                    string k = (string) de.Key;
+                    if (k != "Version")
+                    {
+                        string v = (string) de.Value;
+                        WriteHeaderEntry(k, v);
+                    }
+                }
+
+                DoWrite(nl);
+
+                start = false;
+            }
+
+            if (bufPtr == 3)
+            {
+                Encode(outStream, buf, bufPtr);
+                bufPtr = 0;
+                if ((++chunkCount & 0xf) == 0)
+                {
+                    DoWrite(nl);
+                }
+            }
+
+            crc.Update(b);
+            buf[bufPtr++] = b & 0xff;
+        }
+
+        /**
+         * <b>Note</b>: Dispose does nor Dispose the underlying stream. So it is possible to write
+         * multiple objects using armoring to a single stream.
+         */
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                if (type != null)
+                {
+                    if (bufPtr > 0)
+                    {
+                        Encode(outStream, buf, bufPtr);
+                    }
+
+                    DoWrite(nl + '=');
+
+                    int crcV = crc.Value;
+
+                    buf[0] = ((crcV >> 16) & 0xff);
+                    buf[1] = ((crcV >> 8) & 0xff);
+                    buf[2] = (crcV & 0xff);
+
+                    Encode(outStream, buf, 3);
+
+                    DoWrite(nl);
+                    DoWrite(footerStart);
+                    DoWrite(type);
+                    DoWrite(footerTail);
+                    DoWrite(nl);
+
+                    outStream.Flush();
+
+                    type = null;
+                    start = true;
+                }
+
+                base.Dispose(disposing);
+			}
+        }
+
+		private void WriteHeaderEntry(
+			string	name,
+			string	v)
+        {
+            DoWrite(name + ": " + v + nl);
+        }
+
+		private void DoWrite(
+			string s)
+        {
+            byte[] bs = Strings.ToAsciiByteArray(s);
+			outStream.Write(bs, 0, bs.Length);
+        }
+    }
+}
diff --git a/Crypto/src/bcpg/BcpgInputStream.cs b/Crypto/src/bcpg/BcpgInputStream.cs
new file mode 100644
index 000000000..b4afab901
--- /dev/null
+++ b/Crypto/src/bcpg/BcpgInputStream.cs
@@ -0,0 +1,359 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Reader for PGP objects.</remarks>
+    public class BcpgInputStream
+        : BaseInputStream
+    {
+        private Stream m_in;
+        private bool next = false;
+        private int nextB;
+
+        internal static BcpgInputStream Wrap(
+			Stream inStr)
+        {
+            if (inStr is BcpgInputStream)
+            {
+                return (BcpgInputStream) inStr;
+            }
+
+            return new BcpgInputStream(inStr);
+        }
+
+        private BcpgInputStream(
+			Stream inputStream)
+        {
+            this.m_in = inputStream;
+        }
+
+        public override int ReadByte()
+        {
+            if (next)
+            {
+                next = false;
+                return nextB;
+            }
+
+            return m_in.ReadByte();
+        }
+
+        public override int Read(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+        {
+			// Strangely, when count == 0, we should still attempt to read a byte
+//			if (count == 0)
+//				return 0;
+
+			if (!next)
+				return m_in.Read(buffer, offset, count);
+
+			// We have next byte waiting, so return it
+
+			if (nextB < 0)
+				return 0; // EndOfStream
+
+			if (buffer == null)
+				throw new ArgumentNullException("buffer");
+
+			buffer[offset] = (byte) nextB;
+			next = false;
+
+			return 1;
+        }
+
+		public byte[] ReadAll()
+        {
+			return Streams.ReadAll(this);
+		}
+
+		public void ReadFully(
+            byte[]	buffer,
+            int		off,
+            int		len)
+        {
+			if (Streams.ReadFully(this, buffer, off, len) < len)
+				throw new EndOfStreamException();
+        }
+
+		public void ReadFully(
+            byte[] buffer)
+        {
+            ReadFully(buffer, 0, buffer.Length);
+        }
+
+		/// <summary>Returns the next packet tag in the stream.</summary>
+        public PacketTag NextPacketTag()
+        {
+            if (!next)
+            {
+                try
+                {
+                    nextB = m_in.ReadByte();
+                }
+                catch (EndOfStreamException)
+                {
+                    nextB = -1;
+                }
+
+                next = true;
+            }
+
+            if (nextB >= 0)
+            {
+                if ((nextB & 0x40) != 0)    // new
+                {
+                    return (PacketTag)(nextB & 0x3f);
+                }
+                else    // old
+                {
+                    return (PacketTag)((nextB & 0x3f) >> 2);
+                }
+            }
+
+            return (PacketTag) nextB;
+        }
+
+        public Packet ReadPacket()
+        {
+            int hdr = this.ReadByte();
+
+            if (hdr < 0)
+            {
+                return null;
+            }
+
+            if ((hdr & 0x80) == 0)
+            {
+                throw new IOException("invalid header encountered");
+            }
+
+            bool newPacket = (hdr & 0x40) != 0;
+            PacketTag tag = 0;
+            int bodyLen = 0;
+            bool partial = false;
+
+            if (newPacket)
+            {
+                tag = (PacketTag)(hdr & 0x3f);
+
+                int l = this.ReadByte();
+
+                if (l < 192)
+                {
+                    bodyLen = l;
+                }
+                else if (l <= 223)
+                {
+                    int b = m_in.ReadByte();
+                    bodyLen = ((l - 192) << 8) + (b) + 192;
+                }
+                else if (l == 255)
+                {
+                    bodyLen = (m_in.ReadByte() << 24) | (m_in.ReadByte() << 16)
+                        |  (m_in.ReadByte() << 8)  | m_in.ReadByte();
+                }
+                else
+                {
+                    partial = true;
+                    bodyLen = 1 << (l & 0x1f);
+                }
+            }
+            else
+            {
+                int lengthType = hdr & 0x3;
+
+                tag = (PacketTag)((hdr & 0x3f) >> 2);
+
+                switch (lengthType)
+                {
+                    case 0:
+                        bodyLen = this.ReadByte();
+                        break;
+                    case 1:
+                        bodyLen = (this.ReadByte() << 8) | this.ReadByte();
+                        break;
+                    case 2:
+                        bodyLen = (this.ReadByte() << 24) | (this.ReadByte() << 16)
+                            | (this.ReadByte() << 8) | this.ReadByte();
+                        break;
+                    case 3:
+                        partial = true;
+                        break;
+                    default:
+                        throw new IOException("unknown length type encountered");
+                }
+            }
+
+            BcpgInputStream objStream;
+            if (bodyLen == 0 && partial)
+            {
+                objStream = this;
+            }
+            else
+            {
+                PartialInputStream pis = new PartialInputStream(this, partial, bodyLen);
+                objStream = new BcpgInputStream(pis);
+            }
+
+            switch (tag)
+            {
+                case PacketTag.Reserved:
+                    return new InputStreamPacket(objStream);
+                case PacketTag.PublicKeyEncryptedSession:
+                    return new PublicKeyEncSessionPacket(objStream);
+                case PacketTag.Signature:
+                    return new SignaturePacket(objStream);
+                case PacketTag.SymmetricKeyEncryptedSessionKey:
+                    return new SymmetricKeyEncSessionPacket(objStream);
+                case PacketTag.OnePassSignature:
+                    return new OnePassSignaturePacket(objStream);
+                case PacketTag.SecretKey:
+                    return new SecretKeyPacket(objStream);
+                case PacketTag.PublicKey:
+                    return new PublicKeyPacket(objStream);
+                case PacketTag.SecretSubkey:
+                    return new SecretSubkeyPacket(objStream);
+                case PacketTag.CompressedData:
+                    return new CompressedDataPacket(objStream);
+                case PacketTag.SymmetricKeyEncrypted:
+                    return new SymmetricEncDataPacket(objStream);
+                case PacketTag.Marker:
+                    return new MarkerPacket(objStream);
+                case PacketTag.LiteralData:
+                    return new LiteralDataPacket(objStream);
+                case PacketTag.Trust:
+                    return new TrustPacket(objStream);
+                case PacketTag.UserId:
+                    return new UserIdPacket(objStream);
+                case PacketTag.UserAttribute:
+                    return new UserAttributePacket(objStream);
+                case PacketTag.PublicSubkey:
+                    return new PublicSubkeyPacket(objStream);
+                case PacketTag.SymmetricEncryptedIntegrityProtected:
+                    return new SymmetricEncIntegrityPacket(objStream);
+                case PacketTag.ModificationDetectionCode:
+                    return new ModDetectionCodePacket(objStream);
+                case PacketTag.Experimental1:
+                case PacketTag.Experimental2:
+                case PacketTag.Experimental3:
+                case PacketTag.Experimental4:
+                    return new ExperimentalPacket(tag, objStream);
+                default:
+                    throw new IOException("unknown packet type encountered: " + tag);
+            }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                m_in.Dispose();
+            }
+
+            base.Dispose(disposing);
+        }
+
+		/// <summary>
+		/// A stream that overlays our input stream, allowing the user to only read a segment of it.
+		/// NB: dataLength will be negative if the segment length is in the upper range above 2**31.
+		/// </summary>
+		private class PartialInputStream
+            : BaseInputStream
+        {
+            private BcpgInputStream m_in;
+            private bool partial;
+            private int dataLength;
+
+            internal PartialInputStream(
+                BcpgInputStream	bcpgIn,
+                bool			partial,
+                int				dataLength)
+            {
+                this.m_in = bcpgIn;
+                this.partial = partial;
+                this.dataLength = dataLength;
+            }
+
+			public override int ReadByte()
+			{
+				do
+				{
+					if (dataLength != 0)
+					{
+						int ch = m_in.ReadByte();
+						if (ch < 0)
+						{
+							throw new EndOfStreamException("Premature end of stream in PartialInputStream");
+						}
+						dataLength--;
+						return ch;
+					}
+				}
+				while (partial && ReadPartialDataLength() >= 0);
+
+				return -1;
+			}
+
+			public override int Read(byte[] buffer, int offset, int count)
+			{
+				do
+				{
+					if (dataLength != 0)
+					{
+						int readLen = (dataLength > count || dataLength < 0) ? count : dataLength;
+						int len = m_in.Read(buffer, offset, readLen);
+						if (len < 1)
+						{
+							throw new EndOfStreamException("Premature end of stream in PartialInputStream");
+						}
+						dataLength -= len;
+						return len;
+					}
+				}
+				while (partial && ReadPartialDataLength() >= 0);
+
+				return 0;
+			}
+
+            private int ReadPartialDataLength()
+            {
+                int l = m_in.ReadByte();
+
+				if (l < 0)
+                {
+                    return -1;
+                }
+
+				partial = false;
+
+				if (l < 192)
+                {
+                    dataLength = l;
+                }
+                else if (l <= 223)
+                {
+                    dataLength = ((l - 192) << 8) + (m_in.ReadByte()) + 192;
+                }
+                else if (l == 255)
+                {
+                    dataLength = (m_in.ReadByte() << 24) | (m_in.ReadByte() << 16)
+                        |  (m_in.ReadByte() << 8)  | m_in.ReadByte();
+                }
+                else
+                {
+                    partial = true;
+                    dataLength = 1 << (l & 0x1f);
+                }
+
+                return 0;
+            }
+        }
+    }
+}
diff --git a/Crypto/src/bcpg/BcpgObject.cs b/Crypto/src/bcpg/BcpgObject.cs
new file mode 100644
index 000000000..92811c3d3
--- /dev/null
+++ b/Crypto/src/bcpg/BcpgObject.cs
@@ -0,0 +1,22 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Base class for a PGP object.</remarks>
+    public abstract class BcpgObject
+    {
+        public virtual byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+            BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+			pOut.WriteObject(this);
+
+			return bOut.ToArray();
+        }
+
+		public abstract void Encode(BcpgOutputStream bcpgOut);
+    }
+}
+
diff --git a/Crypto/src/bcpg/BcpgOutputStream.cs b/Crypto/src/bcpg/BcpgOutputStream.cs
new file mode 100644
index 000000000..365053e11
--- /dev/null
+++ b/Crypto/src/bcpg/BcpgOutputStream.cs
@@ -0,0 +1,394 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic output stream.</remarks>
+    public class BcpgOutputStream
+        : BaseOutputStream
+    {
+		internal static BcpgOutputStream Wrap(
+			Stream outStr)
+		{
+			if (outStr is BcpgOutputStream)
+			{
+				return (BcpgOutputStream) outStr;
+			}
+
+			return new BcpgOutputStream(outStr);
+		}
+
+		private Stream outStr;
+        private byte[] partialBuffer;
+        private int partialBufferLength;
+        private int partialPower;
+        private int partialOffset;
+        private const int BufferSizePower = 16; // 2^16 size buffer on long files
+
+		/// <summary>Create a stream representing a general packet.</summary>
+		/// <param name="outStr">Output stream to write to.</param>
+		public BcpgOutputStream(
+            Stream outStr)
+        {
+			if (outStr == null)
+				throw new ArgumentNullException("outStr");
+
+			this.outStr = outStr;
+        }
+
+		/// <summary>Create a stream representing an old style partial object.</summary>
+		/// <param name="outStr">Output stream to write to.</param>
+		/// <param name="tag">The packet tag for the object.</param>
+        public BcpgOutputStream(
+            Stream		outStr,
+            PacketTag	tag)
+        {
+			if (outStr == null)
+				throw new ArgumentNullException("outStr");
+
+			this.outStr = outStr;
+            this.WriteHeader(tag, true, true, 0);
+        }
+
+		/// <summary>Create a stream representing a general packet.</summary>
+		/// <param name="outStr">Output stream to write to.</param>
+		/// <param name="tag">Packet tag.</param>
+		/// <param name="length">Size of chunks making up the packet.</param>
+		/// <param name="oldFormat">If true, the header is written out in old format.</param>
+		public BcpgOutputStream(
+            Stream		outStr,
+            PacketTag	tag,
+            long		length,
+            bool		oldFormat)
+        {
+			if (outStr == null)
+				throw new ArgumentNullException("outStr");
+
+			this.outStr = outStr;
+
+            if (length > 0xFFFFFFFFL)
+            {
+                this.WriteHeader(tag, false, true, 0);
+                this.partialBufferLength = 1 << BufferSizePower;
+                this.partialBuffer = new byte[partialBufferLength];
+				this.partialPower = BufferSizePower;
+				this.partialOffset = 0;
+            }
+            else
+            {
+                this.WriteHeader(tag, oldFormat, false, length);
+            }
+        }
+
+		/// <summary>Create a new style partial input stream buffered into chunks.</summary>
+		/// <param name="outStr">Output stream to write to.</param>
+		/// <param name="tag">Packet tag.</param>
+		/// <param name="length">Size of chunks making up the packet.</param>
+		public BcpgOutputStream(
+            Stream		outStr,
+            PacketTag	tag,
+            long		length)
+        {
+			if (outStr == null)
+				throw new ArgumentNullException("outStr");
+
+            this.outStr = outStr;
+            this.WriteHeader(tag, false, false, length);
+        }
+
+		/// <summary>Create a new style partial input stream buffered into chunks.</summary>
+		/// <param name="outStr">Output stream to write to.</param>
+		/// <param name="tag">Packet tag.</param>
+		/// <param name="buffer">Buffer to use for collecting chunks.</param>
+        public BcpgOutputStream(
+            Stream		outStr,
+            PacketTag	tag,
+            byte[]		buffer)
+        {
+			if (outStr == null)
+				throw new ArgumentNullException("outStr");
+
+            this.outStr = outStr;
+            this.WriteHeader(tag, false, true, 0);
+
+			this.partialBuffer = buffer;
+
+			uint length = (uint) partialBuffer.Length;
+            for (partialPower = 0; length != 1; partialPower++)
+            {
+                length >>= 1;
+            }
+
+			if (partialPower > 30)
+            {
+                throw new IOException("Buffer cannot be greater than 2^30 in length.");
+            }
+            this.partialBufferLength = 1 << partialPower;
+            this.partialOffset = 0;
+        }
+
+		private void WriteNewPacketLength(
+            long bodyLen)
+        {
+            if (bodyLen < 192)
+            {
+                outStr.WriteByte((byte)bodyLen);
+            }
+            else if (bodyLen <= 8383)
+            {
+                bodyLen -= 192;
+
+                outStr.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
+                outStr.WriteByte((byte)bodyLen);
+            }
+            else
+            {
+                outStr.WriteByte(0xff);
+                outStr.WriteByte((byte)(bodyLen >> 24));
+                outStr.WriteByte((byte)(bodyLen >> 16));
+                outStr.WriteByte((byte)(bodyLen >> 8));
+                outStr.WriteByte((byte)bodyLen);
+            }
+        }
+
+        private void WriteHeader(
+            PacketTag	tag,
+            bool		oldPackets,
+            bool		partial,
+            long		bodyLen)
+        {
+            int hdr = 0x80;
+
+            if (partialBuffer != null)
+            {
+                PartialFlush(true);
+                partialBuffer = null;
+            }
+
+            if (oldPackets)
+            {
+                hdr |= ((int) tag) << 2;
+
+                if (partial)
+                {
+                    this.WriteByte((byte)(hdr | 0x03));
+                }
+                else
+                {
+                    if (bodyLen <= 0xff)
+                    {
+                        this.WriteByte((byte) hdr);
+                        this.WriteByte((byte)bodyLen);
+                    }
+                    else if (bodyLen <= 0xffff)
+                    {
+                        this.WriteByte((byte)(hdr | 0x01));
+                        this.WriteByte((byte)(bodyLen >> 8));
+                        this.WriteByte((byte)(bodyLen));
+                    }
+                    else
+                    {
+                        this.WriteByte((byte)(hdr | 0x02));
+                        this.WriteByte((byte)(bodyLen >> 24));
+                        this.WriteByte((byte)(bodyLen >> 16));
+                        this.WriteByte((byte)(bodyLen >> 8));
+                        this.WriteByte((byte)bodyLen);
+                    }
+                }
+            }
+            else
+            {
+                hdr |= 0x40 | (int) tag;
+                this.WriteByte((byte) hdr);
+
+                if (partial)
+                {
+                    partialOffset = 0;
+                }
+                else
+                {
+                    this.WriteNewPacketLength(bodyLen);
+                }
+            }
+        }
+
+        private void PartialFlush(
+            bool isLast)
+        {
+            if (isLast)
+            {
+                WriteNewPacketLength(partialOffset);
+                outStr.Write(partialBuffer, 0, partialOffset);
+            }
+            else
+            {
+                outStr.WriteByte((byte)(0xE0 | partialPower));
+                outStr.Write(partialBuffer, 0, partialBufferLength);
+            }
+
+            partialOffset = 0;
+        }
+
+		private void WritePartial(
+            byte b)
+        {
+            if (partialOffset == partialBufferLength)
+            {
+                PartialFlush(false);
+            }
+
+			partialBuffer[partialOffset++] = b;
+        }
+
+		private void WritePartial(
+            byte[]	buffer,
+            int		off,
+            int		len)
+        {
+            if (partialOffset == partialBufferLength)
+            {
+                PartialFlush(false);
+            }
+
+            if (len <= (partialBufferLength - partialOffset))
+            {
+                Array.Copy(buffer, off, partialBuffer, partialOffset, len);
+                partialOffset += len;
+            }
+            else
+            {
+                int diff = partialBufferLength - partialOffset;
+                Array.Copy(buffer, off, partialBuffer, partialOffset, diff);
+                off += diff;
+                len -= diff;
+                PartialFlush(false);
+                while (len > partialBufferLength)
+                {
+                    Array.Copy(buffer, off, partialBuffer, 0, partialBufferLength);
+                    off += partialBufferLength;
+                    len -= partialBufferLength;
+                    PartialFlush(false);
+                }
+                Array.Copy(buffer, off, partialBuffer, 0, len);
+                partialOffset += len;
+            }
+        }
+        public override void WriteByte(
+			byte value)
+        {
+            if (partialBuffer != null)
+            {
+                WritePartial(value);
+            }
+            else
+            {
+                outStr.WriteByte(value);
+            }
+        }
+        public override void Write(
+            byte[]	buffer,
+            int		offset,
+            int		count)
+        {
+            if (partialBuffer != null)
+            {
+                WritePartial(buffer, offset, count);
+            }
+            else
+            {
+                outStr.Write(buffer, offset, count);
+            }
+        }
+
+		// Additional helper methods to write primitive types
+		internal virtual void WriteShort(
+			short n)
+		{
+			this.Write(
+				(byte)(n >> 8),
+				(byte)n);
+		}
+		internal virtual void WriteInt(
+			int n)
+		{
+			this.Write(
+				(byte)(n >> 24),
+				(byte)(n >> 16),
+				(byte)(n >> 8),
+				(byte)n);
+		}
+		internal virtual void WriteLong(
+			long n)
+		{
+			this.Write(
+				(byte)(n >> 56),
+				(byte)(n >> 48),
+				(byte)(n >> 40),
+				(byte)(n >> 32),
+				(byte)(n >> 24),
+				(byte)(n >> 16),
+				(byte)(n >> 8),
+				(byte)n);
+		}
+
+		public void WritePacket(
+            ContainedPacket p)
+        {
+            p.Encode(this);
+        }
+
+        internal void WritePacket(
+            PacketTag	tag,
+            byte[]		body,
+            bool		oldFormat)
+        {
+            this.WriteHeader(tag, oldFormat, false, body.Length);
+            this.Write(body);
+        }
+
+		public void WriteObject(
+            BcpgObject bcpgObject)
+        {
+            bcpgObject.Encode(this);
+        }
+
+		public void WriteObjects(
+			params BcpgObject[] v)
+		{
+			foreach (BcpgObject o in v)
+			{
+				o.Encode(this);
+			}
+		}
+
+		/// <summary>Flush the underlying stream.</summary>
+        public override void Flush()
+        {
+            outStr.Flush();
+        }
+
+		/// <summary>Finish writing out the current packet without closing the underlying stream.</summary>
+        public void Finish()
+        {
+            if (partialBuffer != null)
+            {
+                PartialFlush(true);
+                partialBuffer = null;
+            }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                this.Finish();
+                outStr.Flush();
+                outStr.Dispose();
+            }
+
+            base.Dispose(disposing);
+        }
+    }
+}
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
new file mode 100644
index 000000000..61159567c
--- /dev/null
+++ b/Crypto/src/bcpg/DsaPublicBcpgKey.cs
@@ -0,0 +1,80 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <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);
+		}
+
+		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>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(p, q, g, y);
+		}
+
+		public BigInteger G
+		{
+			get { return g.Value; }
+		}
+
+		public BigInteger P
+		{
+			get { return p.Value; }
+		}
+
+		public BigInteger Q
+		{
+			get { return q.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
new file mode 100644
index 000000000..32d43149b
--- /dev/null
+++ b/Crypto/src/bcpg/PublicKeyPacket.cs
@@ -0,0 +1,115 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/// <remarks>Basic packet for a PGP public key.</remarks>
+    public class PublicKeyPacket
+        : ContainedPacket //, PublicKeyAlgorithmTag
+    {
+		private int version;
+        private long time;
+        private int validDays;
+        private PublicKeyAlgorithmTag algorithm;
+        private IBcpgKey key;
+
+        internal PublicKeyPacket(
+            BcpgInputStream bcpgIn)
+        {
+            version = bcpgIn.ReadByte();
+
+            time = ((uint)bcpgIn.ReadByte() << 24) | ((uint)bcpgIn.ReadByte() << 16)
+                | ((uint)bcpgIn.ReadByte() << 8) | (uint)bcpgIn.ReadByte();
+
+            if (version <= 3)
+            {
+                validDays = (bcpgIn.ReadByte() << 8) | bcpgIn.ReadByte();
+            }
+
+            algorithm = (PublicKeyAlgorithmTag) bcpgIn.ReadByte();
+
+            switch ((PublicKeyAlgorithmTag) algorithm)
+            {
+                case PublicKeyAlgorithmTag.RsaEncrypt:
+                case PublicKeyAlgorithmTag.RsaGeneral:
+                case PublicKeyAlgorithmTag.RsaSign:
+                    key = new RsaPublicBcpgKey(bcpgIn);
+                    break;
+                case PublicKeyAlgorithmTag.Dsa:
+                    key = new DsaPublicBcpgKey(bcpgIn);
+                    break;
+                case PublicKeyAlgorithmTag.ElGamalEncrypt:
+                case PublicKeyAlgorithmTag.ElGamalGeneral:
+                    key = new ElGamalPublicBcpgKey(bcpgIn);
+                    break;
+                default:
+                    throw new IOException("unknown PGP public key algorithm encountered");
+            }
+        }
+
+		/// <summary>Construct a version 4 public key packet.</summary>
+        public PublicKeyPacket(
+            PublicKeyAlgorithmTag	algorithm,
+            DateTime				time,
+            IBcpgKey				key)
+        {
+			this.version = 4;
+            this.time = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L;
+            this.algorithm = algorithm;
+            this.key = key;
+        }
+
+        public int Version
+        {
+			get { return version; }
+        }
+
+        public PublicKeyAlgorithmTag Algorithm
+        {
+			get { return algorithm; }
+        }
+
+        public int ValidDays
+        {
+			get { return validDays; }
+        }
+
+		public DateTime GetTime()
+        {
+            return DateTimeUtilities.UnixMsToDateTime(time * 1000L);
+        }
+
+        public IBcpgKey Key
+        {
+			get { return key; }
+        }
+
+        public byte[] GetEncodedContents()
+        {
+            MemoryStream bOut = new MemoryStream();
+            BcpgOutputStream pOut = new BcpgOutputStream(bOut);
+
+            pOut.WriteByte((byte) version);
+            pOut.WriteInt((int) time);
+
+			if (version <= 3)
+            {
+                pOut.WriteShort((short) validDays);
+            }
+
+			pOut.WriteByte((byte) algorithm);
+
+			pOut.WriteObject((BcpgObject)key);
+
+			return bOut.ToArray();
+        }
+
+		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
new file mode 100644
index 000000000..7633b1dba
--- /dev/null
+++ b/Crypto/src/bcpg/SymmetricKeyAlgorithmTags.cs
@@ -0,0 +1,20 @@
+namespace Org.BouncyCastle.Bcpg
+{
+    /**
+    * Basic tags for symmetric key algorithms
+    */
+    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
+    }
+}
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
new file mode 100644
index 000000000..bd49d2150
--- /dev/null
+++ b/Crypto/src/bcpg/UserAttributeSubpacket.cs
@@ -0,0 +1,86 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    /**
+    * Basic type for a user attribute sub-packet.
+    */
+    public class UserAttributeSubpacket
+    {
+        private readonly UserAttributeSubpacketTag	type;
+        private readonly byte[]						data;
+
+		internal UserAttributeSubpacket(
+            UserAttributeSubpacketTag	type,
+            byte[]						data)
+        {
+            this.type = type;
+            this.data = data;
+        }
+
+		public UserAttributeSubpacketTag SubpacketType
+        {
+            get { return type; }
+        }
+
+		/**
+        * return the generic data making up the packet.
+        */
+        public byte[] GetData()
+        {
+            return data;
+        }
+
+        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);
+            }
+
+            os.WriteByte((byte) type);
+            os.Write(data, 0, data.Length);
+        }
+
+        public override bool Equals(
+            object obj)
+        {
+            if (obj == this)
+                return true;
+
+			UserAttributeSubpacket other = obj as UserAttributeSubpacket;
+
+			if (other == null)
+				return false;
+
+			return type == other.type
+				&& Arrays.AreEqual(data, other.data);
+        }
+
+		public override int GetHashCode()
+        {
+			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
new file mode 100644
index 000000000..2e5ea0f3e
--- /dev/null
+++ b/Crypto/src/bcpg/UserAttributeSubpacketsReader.cs
@@ -0,0 +1,63 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Bcpg.Attr;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg
+{
+	/**
+	* reader for user attribute sub-packets
+	*/
+	public class UserAttributeSubpacketsParser
+	{
+		private readonly Stream input;
+
+		public UserAttributeSubpacketsParser(
+			Stream input)
+		{
+			this.input = input;
+		}
+
+		public 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 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();
+
+			UserAttributeSubpacketTag type = (UserAttributeSubpacketTag) tag;
+			switch (type)
+			{
+				case UserAttributeSubpacketTag.ImageAttribute:
+					return new ImageAttrib(data);
+			}
+			return new UserAttributeSubpacket(type, 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
new file mode 100644
index 000000000..73490791c
--- /dev/null
+++ b/Crypto/src/bcpg/attr/ImageAttrib.cs
@@ -0,0 +1,68 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Bcpg.Attr
+{
+	/// <remarks>Basic type for a image attribute packet.</remarks>
+    public class ImageAttrib
+		: UserAttributeSubpacket
+    {
+		public enum Format : byte
+		{
+			Jpeg = 1
+		}
+
+		private static readonly byte[] Zeroes = new byte[12];
+
+		private int     hdrLength;
+        private int     _version;
+        private int     _encoding;
+        private byte[]  imageData;
+
+        public ImageAttrib(
+            byte[] data)
+            : base(UserAttributeSubpacketTag.ImageAttribute, data)
+        {
+            hdrLength = ((data[1] & 0xff) << 8) | (data[0] & 0xff);
+            _version = data[2] & 0xff;
+            _encoding = data[3] & 0xff;
+
+            imageData = new byte[data.Length - hdrLength];
+            Array.Copy(data, hdrLength, imageData, 0, imageData.Length);
+        }
+
+		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();
+		}
+
+		public int Version
+        {
+			get { return _version; }
+        }
+
+        public int Encoding
+        {
+			get { return _encoding; }
+        }
+
+		public 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
new file mode 100644
index 000000000..5e388246b
--- /dev/null
+++ b/Crypto/src/bcpg/sig/RevocationKey.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    /// <summary>
+    /// Represents revocation key OpenPGP signature sub packet.
+    /// </summary>
+    public class RevocationKey
+		: SignatureSubpacket
+    {
+		// 1 octet of class, 
+		// 1 octet of public-key algorithm ID, 
+		// 20 octets of fingerprint
+		public RevocationKey(
+			bool	isCritical,
+			byte[]	data)
+			: base(SignatureSubpacketTag.RevocationKey, isCritical, data)
+		{
+		}
+
+		public RevocationKey(
+			bool					isCritical,
+			RevocationKeyTag		signatureClass,
+			PublicKeyAlgorithmTag	keyAlgorithm,
+			byte[]					fingerprint)
+			: base(SignatureSubpacketTag.RevocationKey, isCritical,
+				CreateData(signatureClass, keyAlgorithm, fingerprint))
+		{
+		}
+
+		private static byte[] CreateData(
+			RevocationKeyTag		signatureClass,
+			PublicKeyAlgorithmTag	keyAlgorithm,
+			byte[]					fingerprint)
+		{
+			byte[] data = new byte[2 + fingerprint.Length];
+			data[0] = (byte)signatureClass;
+			data[1] = (byte)keyAlgorithm;
+			Array.Copy(fingerprint, 0, data, 2, fingerprint.Length);
+			return data;
+		}
+
+		public virtual RevocationKeyTag SignatureClass
+		{
+			get { return (RevocationKeyTag)this.GetData()[0]; }
+		}
+
+		public virtual PublicKeyAlgorithmTag Algorithm
+		{
+			get { return (PublicKeyAlgorithmTag)this.GetData()[1]; }
+		}
+
+        public virtual byte[] GetFingerprint()
+		{
+			byte[] data = this.GetData();
+			byte[] fingerprint = new byte[data.Length - 2];
+			Array.Copy(data, 2, fingerprint, 0, fingerprint.Length);
+			return fingerprint;
+		}
+    }
+}
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
new file mode 100644
index 000000000..f32c1f64a
--- /dev/null
+++ b/Crypto/src/bcpg/sig/RevocationReason.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg
+{
+    /// <summary>
+    /// Represents revocation reason OpenPGP signature sub packet.
+    /// </summary>
+    public class RevocationReason
+		: SignatureSubpacket
+    {
+        public RevocationReason(bool isCritical, byte[] data)
+            : base(SignatureSubpacketTag.RevocationReason, isCritical, data)
+        {
+        }
+
+		public RevocationReason(
+			bool				isCritical,
+			RevocationReasonTag	reason,
+			string				description)
+            : base(SignatureSubpacketTag.RevocationReason, isCritical, CreateData(reason, description))
+        {
+        }
+
+        private static byte[] CreateData(
+			RevocationReasonTag	reason,
+			string				description)
+        {
+            byte[] descriptionBytes = Strings.ToUtf8ByteArray(description);
+            byte[] data = new byte[1 + descriptionBytes.Length];
+
+            data[0] = (byte)reason;
+            Array.Copy(descriptionBytes, 0, data, 1, descriptionBytes.Length);
+
+            return data;
+        }
+
+        public virtual RevocationReasonTag GetRevocationReason()
+        {
+            return (RevocationReasonTag)GetData()[0];
+        }
+
+        public virtual string GetRevocationDescription()
+        {
+            byte[] data = GetData();
+            if (data.Length == 1)
+            {
+                return string.Empty;
+            }
+
+            byte[] description = new byte[data.Length - 1];
+            Array.Copy(data, 1, description, 0, description.Length);
+
+            return Strings.FromUtf8ByteArray(description);
+        }
+    }
+}
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
new file mode 100644
index 000000000..2bc8ce5d1
--- /dev/null
+++ b/Crypto/src/cms/CMSAttributeTableGenerationException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Cms
+{
+	public class CmsAttributeTableGenerationException
+		: CmsException
+	{
+		public CmsAttributeTableGenerationException()
+		{
+		}
+
+		public CmsAttributeTableGenerationException(
+			string name)
+			: base(name)
+		{
+		}
+
+		public CmsAttributeTableGenerationException(
+			string		name,
+			Exception	e)
+			: base(name, e)
+		{
+		}
+	}
+}
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
new file mode 100644
index 000000000..0a37ca4f5
--- /dev/null
+++ b/Crypto/src/cms/CMSAuthenticatedDataGenerator.cs
@@ -0,0 +1,156 @@
+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.Generators;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	 * General class for generating a CMS authenticated-data message.
+	 *
+	 * A simple example of usage.
+	 *
+	 * <pre>
+	 *      CMSAuthenticatedDataGenerator  fact = new CMSAuthenticatedDataGenerator();
+	 *
+	 *      fact.addKeyTransRecipient(cert);
+	 *
+	 *      CMSAuthenticatedData         data = fact.generate(content, algorithm, "BC");
+	 * </pre>
+	 */
+	public class CmsAuthenticatedDataGenerator
+	    : CmsAuthenticatedGenerator
+	{
+	    /**
+	     * base constructor
+	     */
+	    public CmsAuthenticatedDataGenerator()
+	    {
+	    }
+
+	    /**
+	     * constructor allowing specific source of randomness
+	     * @param rand instance of SecureRandom to use
+	     */
+	    public CmsAuthenticatedDataGenerator(
+	        SecureRandom rand)
+	        : base(rand)
+	    {
+	    }
+
+	    /**
+	     * generate an enveloped object that contains an CMS Enveloped Data
+	     * object using the given provider and the passed in key generator.
+	     */
+		private CmsAuthenticatedData Generate(
+			CmsProcessable		content,
+			string				macOid,
+			CipherKeyGenerator	keyGen)
+		{
+			AlgorithmIdentifier macAlgId;
+			KeyParameter encKey;
+			Asn1OctetString encContent;
+			Asn1OctetString macResult;
+
+			try
+			{
+				// FIXME Will this work for macs?
+				byte[] encKeyBytes = keyGen.GenerateKey();
+				encKey = ParameterUtilities.CreateKeyParameter(macOid, encKeyBytes);
+
+				Asn1Encodable asn1Params = GenerateAsn1Parameters(macOid, encKeyBytes);
+
+				ICipherParameters cipherParameters;
+				macAlgId = GetAlgorithmIdentifier(
+				macOid, encKey, asn1Params, out cipherParameters);
+
+				IMac mac = MacUtilities.GetMac(macOid);
+				// TODO Confirm no ParametersWithRandom needed
+				// FIXME Only passing key at the moment
+//	            mac.Init(cipherParameters);
+				mac.Init(encKey);
+
+				MemoryStream bOut = new MemoryStream();
+				Stream mOut = new TeeOutputStream(bOut, new MacOutputStream(mac));
+
+				content.Write(mOut);
+
+                mOut.Dispose();
+                bOut.Dispose();
+
+				encContent = new BerOctetString(bOut.ToArray());
+
+				byte[] macOctets = MacUtilities.DoFinal(mac);
+				macResult = new DerOctetString(macOctets);
+			}
+			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("exception decoding algorithm parameters.", e);
+			}
+
+			Asn1EncodableVector recipientInfos = new Asn1EncodableVector();
+
+			foreach (RecipientInfoGenerator rig in recipientInfoGenerators) 
+			{
+				try
+				{
+					recipientInfos.Add(rig.Generate(encKey, rand));
+				}
+				catch (InvalidKeyException e)
+				{
+					throw new CmsException("key inappropriate for algorithm.", e);
+				}
+				catch (GeneralSecurityException e)
+				{
+					throw new CmsException("error making encrypted content.", e);
+				}
+			}
+			
+			ContentInfo eci = new ContentInfo(CmsObjectIdentifiers.Data, encContent);
+			
+			ContentInfo contentInfo = new ContentInfo(
+			CmsObjectIdentifiers.AuthenticatedData,
+			new AuthenticatedData(null, new DerSet(recipientInfos), macAlgId, null, eci, null, macResult, null));
+			
+			return new CmsAuthenticatedData(contentInfo);
+		}
+
+	    /**
+	     * generate an authenticated object that contains an CMS Authenticated Data object
+	     */
+	    public CmsAuthenticatedData Generate(
+	        CmsProcessable	content,
+	        string			encryptionOid)
+	    {
+            try
+            {
+				// FIXME Will this work for macs?
+				CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+				keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+
+				return Generate(content, encryptionOid, keyGen);
+            }
+            catch (SecurityUtilityException e)
+            {
+                throw new CmsException("can't find key generation algorithm.", e);
+            }
+	    }
+	}
+}
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
new file mode 100644
index 000000000..c133ae240
--- /dev/null
+++ b/Crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs
@@ -0,0 +1,275 @@
+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.Generators;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	* General class for generating a CMS authenticated-data message stream.
+	* <p>
+	* A simple example of usage.
+	* <pre>
+	*      CMSAuthenticatedDataStreamGenerator edGen = new CMSAuthenticatedDataStreamGenerator();
+	*
+	*      edGen.addKeyTransRecipient(cert);
+	*
+	*      ByteArrayOutputStream  bOut = new ByteArrayOutputStream();
+	*
+	*      OutputStream out = edGen.open(
+	*                              bOut, CMSAuthenticatedDataGenerator.AES128_CBC, "BC");*
+	*      out.write(data);
+	*
+	*      out.close();
+	* </pre>
+	* </p>
+	*/
+	public class CmsAuthenticatedDataStreamGenerator
+		: CmsAuthenticatedGenerator
+	{
+		// TODO Add support
+//		private object              _originatorInfo = null;
+//		private object              _unprotectedAttributes = null;
+		private int                 _bufferSize;
+		private bool                _berEncodeRecipientSet;
+
+		/**
+		* base constructor
+		*/
+		public CmsAuthenticatedDataStreamGenerator()
+		{
+		}
+
+		/**
+		* constructor allowing specific source of randomness
+		* @param rand instance of SecureRandom to use
+		*/
+		public CmsAuthenticatedDataStreamGenerator(
+			SecureRandom rand)
+			: base(rand)
+		{
+		}
+
+		/**
+		* Set the underlying string size for encapsulated data
+		*
+		* @param bufferSize length of octet strings to buffer the data.
+		*/
+		public void SetBufferSize(
+			int bufferSize)
+		{
+			_bufferSize = bufferSize;
+		}
+
+		/**
+		* Use a BER Set to store the recipient information
+		*/
+		public void SetBerEncodeRecipients(
+			bool berEncodeRecipientSet)
+		{
+			_berEncodeRecipientSet = berEncodeRecipientSet;
+		}
+
+		/**
+		* generate an enveloped object that contains an CMS Enveloped Data
+		* object using the given provider and the passed in key generator.
+		* @throws java.io.IOException
+		*/
+		private Stream Open(
+			Stream				outStr,
+			string				macOid,
+			CipherKeyGenerator	keyGen)
+		{
+			// FIXME Will this work for macs?
+			byte[] encKeyBytes = keyGen.GenerateKey();
+			KeyParameter encKey = ParameterUtilities.CreateKeyParameter(macOid, encKeyBytes);
+
+			Asn1Encodable asn1Params = GenerateAsn1Parameters(macOid, encKeyBytes);
+
+			ICipherParameters cipherParameters;
+			AlgorithmIdentifier macAlgId = GetAlgorithmIdentifier(
+				macOid, encKey, asn1Params, out cipherParameters);
+
+			Asn1EncodableVector recipientInfos = new Asn1EncodableVector();
+
+			foreach (RecipientInfoGenerator rig in recipientInfoGenerators)
+			{
+				try
+				{
+					recipientInfos.Add(rig.Generate(encKey, rand));
+				}
+				catch (InvalidKeyException e)
+				{
+					throw new CmsException("key inappropriate for algorithm.", e);
+				}
+				catch (GeneralSecurityException e)
+				{
+					throw new CmsException("error making encrypted content.", e);
+				}
+			}
+
+			// FIXME Only passing key at the moment
+//			return Open(outStr, macAlgId, cipherParameters, recipientInfos);
+			return Open(outStr, macAlgId, encKey, recipientInfos);
+		}
+
+		protected Stream Open(
+			Stream        			outStr,
+			AlgorithmIdentifier		macAlgId,
+			ICipherParameters		cipherParameters,
+			Asn1EncodableVector		recipientInfos)
+		{
+			try
+			{
+				//
+				// ContentInfo
+				//
+				BerSequenceGenerator cGen = new BerSequenceGenerator(outStr);
+
+				cGen.AddObject(CmsObjectIdentifiers.AuthenticatedData);
+
+				//
+				// Authenticated Data
+				//
+				BerSequenceGenerator authGen = new BerSequenceGenerator(
+					cGen.GetRawOutputStream(), 0, true);
+
+				authGen.AddObject(new DerInteger(AuthenticatedData.CalculateVersion(null)));
+
+				Stream authRaw = authGen.GetRawOutputStream();
+				Asn1Generator recipGen = _berEncodeRecipientSet
+					?	(Asn1Generator) new BerSetGenerator(authRaw)
+					:	new DerSetGenerator(authRaw);
+
+				foreach (Asn1Encodable ae in recipientInfos)
+				{
+					recipGen.AddObject(ae);
+				}
+
+				recipGen.Close();
+
+				authGen.AddObject(macAlgId);
+
+				BerSequenceGenerator eiGen = new BerSequenceGenerator(authRaw);
+				eiGen.AddObject(CmsObjectIdentifiers.Data);
+
+				Stream octetOutputStream = CmsUtilities.CreateBerOctetOutputStream(
+					eiGen.GetRawOutputStream(), 0, false, _bufferSize);
+
+				IMac mac = MacUtilities.GetMac(macAlgId.ObjectID);
+				// TODO Confirm no ParametersWithRandom needed
+	            mac.Init(cipherParameters);
+				Stream mOut = new TeeOutputStream(octetOutputStream, new MacOutputStream(mac));
+
+				return new CmsAuthenticatedDataOutputStream(mOut, mac, cGen, authGen, eiGen);
+			}
+			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("exception decoding algorithm parameters.", e);
+			}
+		}
+
+		/**
+		* generate an enveloped object that contains an CMS Enveloped Data object
+		*/
+		public Stream Open(
+			Stream	outStr,
+			string	encryptionOid)
+		{
+			CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+			keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+
+			return Open(outStr, encryptionOid, keyGen);
+		}
+
+		/**
+		* generate an enveloped object that contains an CMS Enveloped Data object
+		*/
+		public Stream Open(
+			Stream	outStr,
+			string	encryptionOid,
+			int		keySize)
+		{
+			CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+			keyGen.Init(new KeyGenerationParameters(rand, keySize));
+
+			return Open(outStr, encryptionOid, keyGen);
+		}
+
+		private class CmsAuthenticatedDataOutputStream
+			: BaseOutputStream
+		{
+			private readonly Stream					macStream;
+			private readonly IMac					mac;
+			private readonly BerSequenceGenerator	cGen;
+			private readonly BerSequenceGenerator	authGen;
+			private readonly BerSequenceGenerator	eiGen;
+
+			public CmsAuthenticatedDataOutputStream(
+				Stream					macStream,
+				IMac					mac,
+				BerSequenceGenerator	cGen,
+				BerSequenceGenerator	authGen,
+				BerSequenceGenerator	eiGen)
+			{
+				this.macStream = macStream;
+				this.mac = mac;
+				this.cGen = cGen;
+				this.authGen = authGen;
+				this.eiGen = eiGen;
+			}
+
+			public override void WriteByte(
+				byte b)
+			{
+				macStream.WriteByte(b);
+			}
+
+			public override void Write(
+				byte[]	bytes,
+				int		off,
+				int		len)
+			{
+				macStream.Write(bytes, off, len);
+			}
+
+            protected override void Dispose(bool disposing)
+            {
+                if (disposing)
+                {
+                    macStream.Dispose();
+
+                    // TODO Parent context(s) should really be be closed explicitly
+
+                    eiGen.Close();
+
+                    // [TODO] auth attributes go here 
+                    byte[] macOctets = MacUtilities.DoFinal(mac);
+                    authGen.AddObject(new DerOctetString(macOctets));
+                    // [TODO] unauth attributes go here
+
+                    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
new file mode 100644
index 000000000..55d06b5b8
--- /dev/null
+++ b/Crypto/src/cms/CMSCompressedData.cs
@@ -0,0 +1,107 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Cms
+{
+    /**
+    * containing class for an CMS Compressed Data object
+    */
+    public class CmsCompressedData
+    {
+        internal ContentInfo contentInfo;
+
+		public CmsCompressedData(
+            byte[] compressedData)
+            : this(CmsUtilities.ReadContentInfo(compressedData))
+        {
+        }
+
+		public CmsCompressedData(
+            Stream compressedDataStream)
+            : this(CmsUtilities.ReadContentInfo(compressedDataStream))
+        {
+        }
+
+		public CmsCompressedData(
+            ContentInfo contentInfo)
+        {
+            this.contentInfo = contentInfo;
+        }
+
+		/**
+		 * Return the uncompressed content.
+		 *
+		 * @return the uncompressed content
+		 * @throws CmsException if there is an exception uncompressing the data.
+		 */
+		public byte[] GetContent()
+        {
+            CompressedData comData = CompressedData.GetInstance(contentInfo.Content);
+            ContentInfo content = comData.EncapContentInfo;
+
+			Asn1OctetString bytes = (Asn1OctetString) content.Content;
+			ZInputStream zIn = new ZInputStream(bytes.GetOctetStream());
+
+			try
+			{
+				return CmsUtilities.StreamToByteArray(zIn);
+			}
+			catch (IOException e)
+			{
+				throw new CmsException("exception reading compressed stream.", e);
+			}
+			finally
+			{
+                zIn.Dispose();
+			}
+        }
+
+	    /**
+	     * Return the uncompressed content, throwing an exception if the data size
+	     * is greater than the passed in limit. If the content is exceeded getCause()
+	     * on the CMSException will contain a StreamOverflowException
+	     *
+	     * @param limit maximum number of bytes to read
+	     * @return the content read
+	     * @throws CMSException if there is an exception uncompressing the data.
+	     */
+		public byte[] GetContent(int limit)
+		{
+			CompressedData  comData = CompressedData.GetInstance(contentInfo.Content);
+			ContentInfo     content = comData.EncapContentInfo;
+
+			Asn1OctetString bytes = (Asn1OctetString)content.Content;
+
+			ZInputStream zIn = new ZInputStream(new MemoryStream(bytes.GetOctets(), false));
+
+			try
+			{
+				return CmsUtilities.StreamToByteArray(zIn, limit);
+			}
+			catch (IOException e)
+			{
+				throw new CmsException("exception reading compressed stream.", e);
+			}
+		}
+
+		/**
+		 * return the ContentInfo 
+		 */
+		public ContentInfo ContentInfo
+		{
+			get { return contentInfo; }
+		}
+
+		/**
+        * return the ASN.1 encoded representation of this object.
+        */
+        public byte[] GetEncoded()
+        {
+			return contentInfo.GetEncoded();
+        }
+    }
+}
diff --git a/Crypto/src/cms/CMSCompressedDataGenerator.cs b/Crypto/src/cms/CMSCompressedDataGenerator.cs
new file mode 100644
index 000000000..a6381ced6
--- /dev/null
+++ b/Crypto/src/cms/CMSCompressedDataGenerator.cs
@@ -0,0 +1,66 @@
+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.Zlib;
+
+namespace Org.BouncyCastle.Cms
+{
+    /**
+    * General class for generating a compressed CMS message.
+    * <p>
+    * A simple example of usage.</p>
+    * <p>
+    * <pre>
+    *      CMSCompressedDataGenerator fact = new CMSCompressedDataGenerator();
+    *      CMSCompressedData data = fact.Generate(content, algorithm);
+    * </pre>
+	* </p>
+    */
+    public class CmsCompressedDataGenerator
+    {
+        public const string ZLib = "1.2.840.113549.1.9.16.3.8";
+
+		public CmsCompressedDataGenerator()
+        {
+        }
+
+		/**
+        * Generate an object that contains an CMS Compressed Data
+        */
+        public CmsCompressedData Generate(
+            CmsProcessable	content,
+            string			compressionOid)
+        {
+            AlgorithmIdentifier comAlgId;
+            Asn1OctetString comOcts;
+
+            try
+            {
+                MemoryStream bOut = new MemoryStream();
+                ZOutputStream zOut = new ZOutputStream(bOut, JZlib.Z_DEFAULT_COMPRESSION);
+
+				content.Write(zOut);
+
+                zOut.Dispose();
+
+				comAlgId = new AlgorithmIdentifier(new DerObjectIdentifier(compressionOid));
+				comOcts = new BerOctetString(bOut.ToArray());
+            }
+            catch (IOException e)
+            {
+                throw new CmsException("exception encoding data.", e);
+            }
+
+            ContentInfo comContent = new ContentInfo(CmsObjectIdentifiers.Data, comOcts);
+            ContentInfo contentInfo = new ContentInfo(
+                CmsObjectIdentifiers.CompressedData,
+                new CompressedData(comAlgId, comContent));
+
+			return new CmsCompressedData(contentInfo);
+        }
+    }
+}
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
new file mode 100644
index 000000000..13006d4b0
--- /dev/null
+++ b/Crypto/src/cms/CMSCompressedDataStreamGenerator.cs
@@ -0,0 +1,144 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	* General class for generating a compressed CMS message stream.
+	* <p>
+	* A simple example of usage.
+	* </p>
+	* <pre>
+	*      CMSCompressedDataStreamGenerator gen = new CMSCompressedDataStreamGenerator();
+	*
+	*      Stream cOut = gen.Open(outputStream, CMSCompressedDataStreamGenerator.ZLIB);
+	*
+	*      cOut.Write(data);
+	*
+	*      cOut.Close();
+	* </pre>
+	*/
+	public class CmsCompressedDataStreamGenerator
+	{
+		public const string ZLib = "1.2.840.113549.1.9.16.3.8";
+
+		private int _bufferSize;
+		
+		/**
+		* base constructor
+		*/
+		public CmsCompressedDataStreamGenerator()
+		{
+		}
+
+		/**
+		* Set the underlying string size for encapsulated data
+		*
+		* @param bufferSize length of octet strings to buffer the data.
+		*/
+		public void SetBufferSize(
+			int bufferSize)
+		{
+			_bufferSize = bufferSize;
+		}
+
+		public Stream Open(
+			Stream	outStream,
+			string	compressionOID)
+		{
+			return Open(outStream, CmsObjectIdentifiers.Data.Id, compressionOID);
+		}
+
+		public Stream Open(
+			Stream	outStream,
+			string	contentOID,
+			string	compressionOID)
+		{
+			BerSequenceGenerator sGen = new BerSequenceGenerator(outStream);
+
+			sGen.AddObject(CmsObjectIdentifiers.CompressedData);
+
+			//
+			// Compressed Data
+			//
+			BerSequenceGenerator cGen = new BerSequenceGenerator(
+				sGen.GetRawOutputStream(), 0, true);
+
+			// CMSVersion
+			cGen.AddObject(new DerInteger(0));
+
+			// CompressionAlgorithmIdentifier
+			cGen.AddObject(new AlgorithmIdentifier(new DerObjectIdentifier(ZLib)));
+
+			//
+			// Encapsulated ContentInfo
+			//
+			BerSequenceGenerator eiGen = new BerSequenceGenerator(cGen.GetRawOutputStream());
+
+			eiGen.AddObject(new DerObjectIdentifier(contentOID));
+
+			Stream octetStream = CmsUtilities.CreateBerOctetOutputStream(
+				eiGen.GetRawOutputStream(), 0, true, _bufferSize);
+
+			return new CmsCompressedOutputStream(
+				new ZOutputStream(octetStream, JZlib.Z_DEFAULT_COMPRESSION), sGen, cGen, eiGen);
+		}
+
+		private class CmsCompressedOutputStream
+			: BaseOutputStream
+		{
+			private ZOutputStream _out;
+			private BerSequenceGenerator _sGen;
+			private BerSequenceGenerator _cGen;
+			private BerSequenceGenerator _eiGen;
+
+			internal CmsCompressedOutputStream(
+				ZOutputStream			outStream,
+				BerSequenceGenerator	sGen,
+				BerSequenceGenerator	cGen,
+				BerSequenceGenerator	eiGen)
+			{
+				_out = outStream;
+				_sGen = sGen;
+				_cGen = cGen;
+				_eiGen = eiGen;
+			}
+
+			public override void WriteByte(
+				byte b)
+			{
+				_out.WriteByte(b);
+			}
+
+			public override void Write(
+				byte[]	bytes,
+				int		off,
+				int		len)
+			{
+				_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);
+            }
+        }
+	}
+}
diff --git a/Crypto/src/cms/CMSContentInfoParser.cs b/Crypto/src/cms/CMSContentInfoParser.cs
new file mode 100644
index 000000000..5b1606394
--- /dev/null
+++ b/Crypto/src/cms/CMSContentInfoParser.cs
@@ -0,0 +1,47 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+
+namespace Org.BouncyCastle.Cms
+{
+	public class CmsContentInfoParser
+	{
+		protected ContentInfoParser	contentInfo;
+		protected Stream data;
+
+		protected CmsContentInfoParser(
+			Stream data)
+		{
+			if (data == null)
+				throw new ArgumentNullException("data");
+
+			this.data = data;
+
+			try
+			{
+				Asn1StreamParser inStream = new Asn1StreamParser(data);
+
+				this.contentInfo = new ContentInfoParser((Asn1SequenceParser)inStream.ReadObject());
+			}
+			catch (IOException e)
+			{
+				throw new CmsException("IOException reading content.", e);
+			}
+			catch (InvalidCastException e)
+			{
+				throw new CmsException("Unexpected object reading content.", e);
+			}
+		}
+
+		/**
+		* Close the underlying data stream.
+		* @throws IOException if the close fails.
+		*/
+		public void Close()
+		{
+            this.data.Dispose();
+		}
+	}
+}
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
new file mode 100644
index 000000000..5071af4ad
--- /dev/null
+++ b/Crypto/src/cms/CMSEnvelopedDataGenerator.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+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.Date;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+    /// <remarks>
+    /// 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);
+    /// </pre>
+    /// </remarks>
+    public class CmsEnvelopedDataGenerator
+		: CmsEnvelopedGenerator
+    {
+		public CmsEnvelopedDataGenerator()
+        {
+        }
+
+		/// <summary>Constructor allowing specific source of randomness</summary>
+		/// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+		public CmsEnvelopedDataGenerator(
+			SecureRandom rand)
+			: base(rand)
+		{
+		}
+
+		/// <summary>
+		/// Generate an enveloped object that contains a CMS Enveloped Data
+		/// object using the passed in key generator.
+		/// </summary>
+        private CmsEnvelopedData Generate(
+            CmsProcessable		content,
+            string				encryptionOid,
+            CipherKeyGenerator	keyGen)
+        {
+            AlgorithmIdentifier encAlgId = null;
+			KeyParameter encKey;
+            Asn1OctetString encContent;
+
+			try
+			{
+				byte[] encKeyBytes = keyGen.GenerateKey();
+				encKey = ParameterUtilities.CreateKeyParameter(encryptionOid, encKeyBytes);
+
+				Asn1Encodable asn1Params = GenerateAsn1Parameters(encryptionOid, encKeyBytes);
+
+				ICipherParameters cipherParameters;
+				encAlgId = GetAlgorithmIdentifier(
+					encryptionOid, encKey, asn1Params, out cipherParameters);
+
+				IBufferedCipher cipher = CipherUtilities.GetCipher(encryptionOid);
+				cipher.Init(true, new ParametersWithRandom(cipherParameters, rand));
+
+				MemoryStream bOut = new MemoryStream();
+				CipherStream cOut = new CipherStream(bOut, null, cipher);
+
+				content.Write(cOut);
+
+                cOut.Dispose();
+
+				encContent = new BerOctetString(bOut.ToArray());
+			}
+			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("exception decoding algorithm parameters.", e);
+			}
+
+
+			Asn1EncodableVector recipientInfos = new Asn1EncodableVector();
+
+            foreach (RecipientInfoGenerator rig in recipientInfoGenerators)
+            {
+                try
+                {
+                    recipientInfos.Add(rig.Generate(encKey, rand));
+                }
+                catch (InvalidKeyException e)
+                {
+                    throw new CmsException("key inappropriate for algorithm.", e);
+                }
+                catch (GeneralSecurityException e)
+                {
+                    throw new CmsException("error making encrypted content.", e);
+                }
+            }
+
+            EncryptedContentInfo eci = new EncryptedContentInfo(
+                CmsObjectIdentifiers.Data,
+                encAlgId,
+                encContent);
+
+			Asn1Set unprotectedAttrSet = null;
+            if (unprotectedAttributeGenerator != null)
+            {
+                Asn1.Cms.AttributeTable attrTable = unprotectedAttributeGenerator.GetAttributes(Platform.CreateHashtable());
+
+                unprotectedAttrSet = new BerSet(attrTable.ToAsn1EncodableVector());
+            }
+
+			ContentInfo contentInfo = new ContentInfo(
+                CmsObjectIdentifiers.EnvelopedData,
+                new EnvelopedData(null, new DerSet(recipientInfos), eci, unprotectedAttrSet));
+
+            return new CmsEnvelopedData(contentInfo);
+        }
+
+		/// <summary>Generate an enveloped object that contains an CMS Enveloped Data object.</summary>
+        public CmsEnvelopedData Generate(
+            CmsProcessable	content,
+            string			encryptionOid)
+        {
+            try
+            {
+				CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+				keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+
+				return Generate(content, encryptionOid, keyGen);
+            }
+            catch (SecurityUtilityException e)
+            {
+                throw new CmsException("can't find key generation algorithm.", e);
+            }
+        }
+
+		/// <summary>Generate an enveloped object that contains an CMS Enveloped Data object.</summary>
+        public CmsEnvelopedData Generate(
+            CmsProcessable  content,
+            string          encryptionOid,
+            int             keySize)
+        {
+            try
+            {
+				CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+				keyGen.Init(new KeyGenerationParameters(rand, keySize));
+
+				return Generate(content, encryptionOid, keyGen);
+            }
+            catch (SecurityUtilityException e)
+            {
+                throw new CmsException("can't find key generation algorithm.", e);
+            }
+        }
+    }
+}
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
new file mode 100644
index 000000000..820ddfe16
--- /dev/null
+++ b/Crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs
@@ -0,0 +1,285 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	* General class for generating a CMS enveloped-data message stream.
+	* <p>
+	* A simple example of usage.
+	* <pre>
+	*      CmsEnvelopedDataStreamGenerator edGen = new CmsEnvelopedDataStreamGenerator();
+	*
+	*      edGen.AddKeyTransRecipient(cert);
+	*
+	*      MemoryStream  bOut = new MemoryStream();
+	*
+	*      Stream out = edGen.Open(
+	*                              bOut, CMSEnvelopedDataGenerator.AES128_CBC);*
+	*      out.Write(data);
+	*
+	*      out.Close();
+	* </pre>
+	* </p>
+	*/
+	public class CmsEnvelopedDataStreamGenerator
+		: CmsEnvelopedGenerator
+	{
+		private object	_originatorInfo = null;
+		private object	_unprotectedAttributes = null;
+		private int		_bufferSize;
+		private bool	_berEncodeRecipientSet;
+
+		public CmsEnvelopedDataStreamGenerator()
+		{
+		}
+
+		/// <summary>Constructor allowing specific source of randomness</summary>
+		/// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+		public CmsEnvelopedDataStreamGenerator(
+			SecureRandom rand)
+			: base(rand)
+		{
+		}
+
+		/// <summary>Set the underlying string size for encapsulated data.</summary>
+		/// <param name="bufferSize">Length of octet strings to buffer the data.</param>
+		public void SetBufferSize(
+			int bufferSize)
+		{
+			_bufferSize = bufferSize;
+		}
+
+		/// <summary>Use a BER Set to store the recipient information.</summary>
+		public void SetBerEncodeRecipients(
+			bool berEncodeRecipientSet)
+		{
+			_berEncodeRecipientSet = berEncodeRecipientSet;
+		}
+
+		private DerInteger Version
+		{
+			get
+			{
+				int version = (_originatorInfo != null || _unprotectedAttributes != null)
+					?	2
+					:	0;
+
+				return new DerInteger(version);
+			}
+		}
+
+		/// <summary>
+		/// Generate an enveloped object that contains an CMS Enveloped Data
+		/// object using the passed in key generator.
+		/// </summary>
+		private Stream Open(
+			Stream				outStream,
+			string				encryptionOid,
+			CipherKeyGenerator	keyGen)
+		{
+			byte[] encKeyBytes = keyGen.GenerateKey();
+			KeyParameter encKey = ParameterUtilities.CreateKeyParameter(encryptionOid, encKeyBytes);
+
+			Asn1Encodable asn1Params = GenerateAsn1Parameters(encryptionOid, encKeyBytes);
+
+			ICipherParameters cipherParameters;
+			AlgorithmIdentifier encAlgID = GetAlgorithmIdentifier(
+				encryptionOid, encKey, asn1Params, out cipherParameters);
+
+			Asn1EncodableVector recipientInfos = new Asn1EncodableVector();
+
+			foreach (RecipientInfoGenerator rig in recipientInfoGenerators)
+			{
+				try
+				{
+					recipientInfos.Add(rig.Generate(encKey, rand));
+				}
+				catch (InvalidKeyException e)
+				{
+					throw new CmsException("key inappropriate for algorithm.", e);
+				}
+				catch (GeneralSecurityException e)
+				{
+					throw new CmsException("error making encrypted content.", e);
+				}
+			}
+
+			return Open(outStream, encAlgID, cipherParameters, recipientInfos);
+		}
+
+		private Stream Open(
+			Stream				outStream,
+			AlgorithmIdentifier	encAlgID,
+			ICipherParameters	cipherParameters,
+			Asn1EncodableVector	recipientInfos)
+		{
+			try
+			{
+				//
+				// ContentInfo
+				//
+				BerSequenceGenerator cGen = new BerSequenceGenerator(outStream);
+
+				cGen.AddObject(CmsObjectIdentifiers.EnvelopedData);
+
+				//
+				// Encrypted Data
+				//
+				BerSequenceGenerator envGen = new BerSequenceGenerator(
+					cGen.GetRawOutputStream(), 0, true);
+
+				envGen.AddObject(this.Version);
+
+				Stream envRaw = envGen.GetRawOutputStream();
+				Asn1Generator recipGen = _berEncodeRecipientSet
+					?	(Asn1Generator) new BerSetGenerator(envRaw)
+					:	new DerSetGenerator(envRaw);
+
+				foreach (Asn1Encodable ae in recipientInfos)
+				{
+					recipGen.AddObject(ae);
+				}
+
+				recipGen.Close();
+
+				BerSequenceGenerator eiGen = new BerSequenceGenerator(envRaw);
+				eiGen.AddObject(CmsObjectIdentifiers.Data);
+				eiGen.AddObject(encAlgID);
+
+				Stream octetOutputStream = CmsUtilities.CreateBerOctetOutputStream(
+					eiGen.GetRawOutputStream(), 0, false, _bufferSize);
+
+				IBufferedCipher cipher = CipherUtilities.GetCipher(encAlgID.ObjectID);
+				cipher.Init(true, new ParametersWithRandom(cipherParameters, rand));
+				CipherStream cOut = new CipherStream(octetOutputStream, null, cipher);
+
+				return new CmsEnvelopedDataOutputStream(this, cOut, cGen, envGen, eiGen);
+			}
+			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("exception decoding algorithm parameters.", e);
+			}
+		}
+
+		/**
+		* generate an enveloped object that contains an CMS Enveloped Data object
+		* @throws IOException
+		*/
+		public Stream Open(
+			Stream	outStream,
+			string	encryptionOid)
+		{
+			CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+			keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+
+			return Open(outStream, encryptionOid, keyGen);
+		}
+
+		/**
+		* generate an enveloped object that contains an CMS Enveloped Data object
+		* @throws IOException
+		*/
+		public Stream Open(
+			Stream	outStream,
+			string	encryptionOid,
+			int		keySize)
+		{
+			CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
+
+			keyGen.Init(new KeyGenerationParameters(rand, keySize));
+
+			return Open(outStream, encryptionOid, keyGen);
+		}
+
+		private class CmsEnvelopedDataOutputStream
+			: BaseOutputStream
+		{
+            private readonly CmsEnvelopedGenerator _outer;
+
+			private readonly CipherStream			_out;
+			private readonly BerSequenceGenerator	_cGen;
+			private readonly BerSequenceGenerator	_envGen;
+			private readonly BerSequenceGenerator	_eiGen;
+
+			public CmsEnvelopedDataOutputStream(
+				CmsEnvelopedGenerator	outer,
+				CipherStream			outStream,
+				BerSequenceGenerator	cGen,
+				BerSequenceGenerator	envGen,
+				BerSequenceGenerator	eiGen)
+			{
+				_outer = outer;
+				_out = outStream;
+				_cGen = cGen;
+				_envGen = envGen;
+				_eiGen = eiGen;
+			}
+
+			public override void WriteByte(
+				byte b)
+			{
+				_out.WriteByte(b);
+			}
+
+			public override void Write(
+				byte[]	bytes,
+				int		off,
+				int		len)
+			{
+				_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();
+
+                    if (_outer.unprotectedAttributeGenerator != null)
+                    {
+                        Asn1.Cms.AttributeTable attrTable = _outer.unprotectedAttributeGenerator.GetAttributes(Platform.CreateHashtable());
+
+                        Asn1Set unprotectedAttrs = new BerSet(attrTable.ToAsn1EncodableVector());
+
+                        _envGen.AddObject(new DerTaggedObject(false, 1, unprotectedAttrs));
+                    }
+
+                    _envGen.Close();
+                    _cGen.Close();
+                }
+
+                base.Dispose(disposing);
+            }
+		}
+	}
+}
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
new file mode 100644
index 000000000..1d1cd82e3
--- /dev/null
+++ b/Crypto/src/cms/CMSException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Cms
+{
+		public class CmsException
+			: Exception
+		{
+		public CmsException()
+		{
+		}
+
+		public CmsException(
+			string msg)
+			: base(msg)
+		{
+		}
+
+		public CmsException(
+			string		msg,
+			Exception	e)
+			: base(msg, e)
+		{
+		}
+	}
+}
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
new file mode 100644
index 000000000..548dc8efb
--- /dev/null
+++ b/Crypto/src/cms/CMSProcessableFile.cs
@@ -0,0 +1,57 @@
+#if !PORTABLE
+
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	* a holding class for a file of data to be processed.
+	*/
+	public class CmsProcessableFile
+		: CmsProcessable, CmsReadable
+	{
+		private const int DefaultBufSize = 32 * 1024;
+
+		private readonly FileInfo	_file;
+		private readonly int		_bufSize;
+
+		public CmsProcessableFile(
+			FileInfo file)
+			: this(file, DefaultBufSize)
+		{
+		}
+
+		public CmsProcessableFile(
+			FileInfo	file,
+			int			bufSize)
+		{
+			_file = file;
+			_bufSize = bufSize;
+		}
+
+		public virtual Stream GetInputStream()
+		{
+			return new FileStream(
+				_file.FullName, FileMode.Open, FileAccess.Read, FileShare.Read, _bufSize);
+		}
+
+		public virtual void Write(
+			Stream zOut)
+		{
+			Stream inStr = GetInputStream();
+			Streams.PipeAll(inStr, zOut);
+			inStr.Close();
+		}
+
+		/// <returns>The file handle</returns>
+		[Obsolete]
+		public virtual object GetContent()
+		{
+			return _file;
+		}
+	}
+}
+#endif
\ No newline at end of file
diff --git a/Crypto/src/cms/CMSProcessableInputStream.cs b/Crypto/src/cms/CMSProcessableInputStream.cs
new file mode 100644
index 000000000..d10d059c6
--- /dev/null
+++ b/Crypto/src/cms/CMSProcessableInputStream.cs
@@ -0,0 +1,52 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	public class CmsProcessableInputStream
+		: CmsProcessable, CmsReadable
+	{
+		private Stream input;
+		private bool used = false;
+
+		public CmsProcessableInputStream(
+			Stream input)
+		{
+			this.input = input;
+		}
+
+		public Stream GetInputStream()
+		{
+			CheckSingleUsage();
+
+			return input;
+		}
+
+		public void Write(Stream output)
+		{
+			CheckSingleUsage();
+
+			Streams.PipeAll(input, output);
+			input.Dispose();
+		}
+
+		[Obsolete]
+		public object GetContent()
+		{
+			return GetInputStream();
+		}
+
+		private void CheckSingleUsage()
+		{
+			lock (this)
+			{
+				if (used)
+					throw new InvalidOperationException("CmsProcessableInputStream can only be used once");
+
+				used = true;
+			}
+		}
+	}
+}
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
new file mode 100644
index 000000000..5b68c785d
--- /dev/null
+++ b/Crypto/src/cms/CMSSignedDataGenerator.cs
@@ -0,0 +1,551 @@
+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.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+    /**
+     * general class for generating a pkcs7-signature message.
+     * <p>
+     * A simple example of usage.
+     *
+     * <pre>
+     *      IX509Store certs...
+     *      IX509Store crls...
+     *      CmsSignedDataGenerator gen = new CmsSignedDataGenerator();
+     *
+     *      gen.AddSigner(privKey, cert, CmsSignedGenerator.DigestSha1);
+     *      gen.AddCertificates(certs);
+     *      gen.AddCrls(crls);
+     *
+     *      CmsSignedData data = gen.Generate(content);
+     * </pre>
+	 * </p>
+     */
+    public class CmsSignedDataGenerator
+        : CmsSignedGenerator
+    {
+		private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
+
+		private readonly IList signerInfs = Platform.CreateArrayList();
+
+		private class SignerInf
+        {
+            private readonly CmsSignedGenerator outer;
+
+			private readonly AsymmetricKeyParameter		key;
+			private readonly SignerIdentifier			signerIdentifier;
+			private readonly string						digestOID;
+			private readonly string						encOID;
+			private readonly CmsAttributeTableGenerator	sAttr;
+			private readonly CmsAttributeTableGenerator	unsAttr;
+			private readonly Asn1.Cms.AttributeTable	baseSignedTable;
+
+			internal SignerInf(
+                CmsSignedGenerator			outer,
+	            AsymmetricKeyParameter		key,
+	            SignerIdentifier			signerIdentifier,
+	            string						digestOID,
+	            string						encOID,
+	            CmsAttributeTableGenerator	sAttr,
+	            CmsAttributeTableGenerator	unsAttr,
+	            Asn1.Cms.AttributeTable		baseSignedTable)
+	        {
+                this.outer = outer;
+                this.key = key;
+                this.signerIdentifier = signerIdentifier;
+                this.digestOID = digestOID;
+                this.encOID = encOID;
+	            this.sAttr = sAttr;
+	            this.unsAttr = unsAttr;
+	            this.baseSignedTable = baseSignedTable;
+            }
+
+			internal AlgorithmIdentifier DigestAlgorithmID
+			{
+				get { return new AlgorithmIdentifier(new DerObjectIdentifier(digestOID), DerNull.Instance); }
+			}
+
+			internal CmsAttributeTableGenerator SignedAttributes
+            {
+				get { return sAttr; }
+            }
+
+            internal CmsAttributeTableGenerator UnsignedAttributes
+            {
+				get { return unsAttr; }
+            }
+
+			internal SignerInfo ToSignerInfo(
+                DerObjectIdentifier	contentType,
+                CmsProcessable		content,
+				SecureRandom		random)
+            {
+                AlgorithmIdentifier digAlgId = DigestAlgorithmID;
+				string digestName = Helper.GetDigestAlgName(digestOID);
+				IDigest dig = Helper.GetDigestInstance(digestName);
+
+				string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID);
+				ISigner sig = Helper.GetSignatureInstance(signatureName);
+
+				// TODO Optimise the case where more than one signer with same digest
+				if (content != null)
+                {
+                    content.Write(new DigOutputStream(dig));
+				}
+
+				byte[] hash = DigestUtilities.DoFinal(dig);
+				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);
+#else
+				Stream sigStr = new BufferedStream(new SigOutputStream(sig));
+#endif
+
+				Asn1Set signedAttr = null;
+				if (sAttr != null)
+				{
+					IDictionary parameters = outer.GetBaseParameters(contentType, digAlgId, hash);
+
+//					Asn1.Cms.AttributeTable signed = sAttr.GetAttributes(Collections.unmodifiableMap(parameters));
+					Asn1.Cms.AttributeTable signed = sAttr.GetAttributes(parameters);
+
+                    if (contentType == null) //counter signature
+                    {
+                        if (signed != null && signed[CmsAttributes.ContentType] != null)
+                        {
+                            IDictionary tmpSigned = signed.ToDictionary();
+                            tmpSigned.Remove(CmsAttributes.ContentType);
+                            signed = new Asn1.Cms.AttributeTable(tmpSigned);
+                        }
+                    }
+
+					// TODO Validate proposed signed attributes
+
+					signedAttr = outer.GetAttributeSet(signed);
+
+					// sig must be composed from the DER encoding.
+					new DerOutputStream(sigStr).WriteObject(signedAttr);
+				}
+                else if (content != null)
+                {
+					// TODO Use raw signature of the hash value instead
+					content.Write(sigStr);
+                }
+
+                sigStr.Dispose();
+				byte[] sigBytes = sig.GenerateSignature();
+
+				Asn1Set unsignedAttr = null;
+				if (unsAttr != null)
+				{
+					IDictionary baseParameters = outer.GetBaseParameters(contentType, digAlgId, hash);
+					baseParameters[CmsAttributeTableParameter.Signature] = sigBytes.Clone();
+
+//					Asn1.Cms.AttributeTable unsigned = unsAttr.GetAttributes(Collections.unmodifiableMap(baseParameters));
+					Asn1.Cms.AttributeTable unsigned = unsAttr.GetAttributes(baseParameters);
+
+					// TODO Validate proposed unsigned attributes
+
+					unsignedAttr = outer.GetAttributeSet(unsigned);
+				}
+
+				// TODO[RSAPSS] Need the ability to specify non-default parameters
+				Asn1Encodable sigX509Parameters = SignerUtilities.GetDefaultX509Parameters(signatureName);
+				AlgorithmIdentifier encAlgId = CmsSignedGenerator.GetEncAlgorithmIdentifier(
+					new DerObjectIdentifier(encOID), sigX509Parameters);
+				
+                return new SignerInfo(signerIdentifier, digAlgId,
+                    signedAttr, encAlgId, new DerOctetString(sigBytes), unsignedAttr);
+            }
+        }
+
+		public CmsSignedDataGenerator()
+        {
+        }
+
+		/// <summary>Constructor allowing specific source of randomness</summary>
+		/// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+		public CmsSignedDataGenerator(
+			SecureRandom rand)
+			: base(rand)
+		{
+		}
+
+		/**
+        * add a signer - no attributes other than the default ones will be
+        * provided here.
+		*
+		* @param key signing key to use
+		* @param cert certificate containing corresponding public key
+		* @param digestOID digest algorithm OID
+        */
+        public void AddSigner(
+            AsymmetricKeyParameter	privateKey,
+            X509Certificate			cert,
+            string					digestOID)
+        {
+        	AddSigner(privateKey, cert, GetEncOid(privateKey, digestOID), digestOID);
+		}
+
+		/**
+		 * add a signer, specifying the digest encryption algorithm to use - no attributes other than the default ones will be
+		 * provided here.
+		 *
+		 * @param key signing key to use
+		 * @param cert certificate containing corresponding public key
+		 * @param encryptionOID digest encryption algorithm OID
+		 * @param digestOID digest algorithm OID
+		 */
+		public void AddSigner(
+			AsymmetricKeyParameter	privateKey,
+			X509Certificate			cert,
+			string					encryptionOID,
+			string					digestOID)
+		{
+			doAddSigner(privateKey, GetSignerIdentifier(cert), encryptionOID, digestOID,
+				new DefaultSignedAttributeTableGenerator(), null, null);
+		}
+
+	    /**
+	     * add a signer - no attributes other than the default ones will be
+	     * provided here.
+	     */
+	    public void AddSigner(
+            AsymmetricKeyParameter	privateKey,
+	        byte[]					subjectKeyID,
+            string					digestOID)
+	    {
+			AddSigner(privateKey, subjectKeyID, GetEncOid(privateKey, digestOID), digestOID);
+	    }
+
+		/**
+		 * add a signer, specifying the digest encryption algorithm to use - no attributes other than the default ones will be
+		 * provided here.
+		 */
+		public void AddSigner(
+			AsymmetricKeyParameter	privateKey,
+			byte[]					subjectKeyID,
+			string					encryptionOID,
+			string					digestOID)
+		{
+			doAddSigner(privateKey, GetSignerIdentifier(subjectKeyID), encryptionOID, digestOID,
+				new DefaultSignedAttributeTableGenerator(), null, null);
+		}
+
+        /**
+        * add a signer with extra signed/unsigned attributes.
+		*
+		* @param key signing key to use
+		* @param cert certificate containing corresponding public key
+		* @param digestOID digest algorithm OID
+		* @param signedAttr table of attributes to be included in signature
+		* @param unsignedAttr table of attributes to be included as unsigned
+        */
+        public void AddSigner(
+            AsymmetricKeyParameter	privateKey,
+            X509Certificate			cert,
+            string					digestOID,
+            Asn1.Cms.AttributeTable	signedAttr,
+            Asn1.Cms.AttributeTable	unsignedAttr)
+        {
+			AddSigner(privateKey, cert, GetEncOid(privateKey, digestOID), digestOID,
+				signedAttr, unsignedAttr);
+		}
+
+		/**
+		 * add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes.
+		 *
+		 * @param key signing key to use
+		 * @param cert certificate containing corresponding public key
+		 * @param encryptionOID digest encryption algorithm OID
+		 * @param digestOID digest algorithm OID
+		 * @param signedAttr table of attributes to be included in signature
+		 * @param unsignedAttr table of attributes to be included as unsigned
+		 */
+		public void AddSigner(
+			AsymmetricKeyParameter	privateKey,
+			X509Certificate			cert,
+			string					encryptionOID,
+			string					digestOID,
+			Asn1.Cms.AttributeTable	signedAttr,
+			Asn1.Cms.AttributeTable	unsignedAttr)
+		{
+			doAddSigner(privateKey, GetSignerIdentifier(cert), encryptionOID, digestOID,
+				new DefaultSignedAttributeTableGenerator(signedAttr),
+				new SimpleAttributeTableGenerator(unsignedAttr),
+				signedAttr);
+		}
+
+	    /**
+	     * add a signer with extra signed/unsigned attributes.
+		 *
+		 * @param key signing key to use
+		 * @param subjectKeyID subjectKeyID of corresponding public key
+		 * @param digestOID digest algorithm OID
+		 * @param signedAttr table of attributes to be included in signature
+		 * @param unsignedAttr table of attributes to be included as unsigned
+	     */
+		public void AddSigner(
+			AsymmetricKeyParameter	privateKey,
+			byte[]					subjectKeyID,
+			string					digestOID,
+			Asn1.Cms.AttributeTable	signedAttr,
+			Asn1.Cms.AttributeTable	unsignedAttr)
+		{
+			AddSigner(privateKey, subjectKeyID, GetEncOid(privateKey, digestOID), digestOID,
+				signedAttr, unsignedAttr); 
+		}
+
+		/**
+		 * add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes.
+		 *
+		 * @param key signing key to use
+		 * @param subjectKeyID subjectKeyID of corresponding public key
+		 * @param encryptionOID digest encryption algorithm OID
+		 * @param digestOID digest algorithm OID
+		 * @param signedAttr table of attributes to be included in signature
+		 * @param unsignedAttr table of attributes to be included as unsigned
+		 */
+		public void AddSigner(
+			AsymmetricKeyParameter	privateKey,
+			byte[]					subjectKeyID,
+			string					encryptionOID,
+			string					digestOID,
+			Asn1.Cms.AttributeTable	signedAttr,
+			Asn1.Cms.AttributeTable	unsignedAttr)
+		{
+			doAddSigner(privateKey, GetSignerIdentifier(subjectKeyID), encryptionOID, digestOID,
+				new DefaultSignedAttributeTableGenerator(signedAttr),
+				new SimpleAttributeTableGenerator(unsignedAttr),
+				signedAttr);
+		}
+
+		/**
+		 * add a signer with extra signed/unsigned attributes based on generators.
+		 */
+		public void AddSigner(
+			AsymmetricKeyParameter		privateKey,
+			X509Certificate				cert,
+			string						digestOID,
+			CmsAttributeTableGenerator	signedAttrGen,
+			CmsAttributeTableGenerator	unsignedAttrGen)
+		{
+			AddSigner(privateKey, cert, GetEncOid(privateKey, digestOID), digestOID,
+				signedAttrGen, unsignedAttrGen);
+		}
+
+		/**
+		 * add a signer, specifying the digest encryption algorithm, with extra signed/unsigned attributes based on generators.
+		 */
+		public void AddSigner(
+			AsymmetricKeyParameter		privateKey,
+			X509Certificate				cert,
+			string						encryptionOID,
+			string						digestOID,
+			CmsAttributeTableGenerator	signedAttrGen,
+			CmsAttributeTableGenerator	unsignedAttrGen)
+		{
+			doAddSigner(privateKey, GetSignerIdentifier(cert), encryptionOID, digestOID, signedAttrGen,
+				unsignedAttrGen, null);
+		}
+
+	    /**
+	     * add a signer with extra signed/unsigned attributes based on generators.
+	     */
+	    public void AddSigner(
+			AsymmetricKeyParameter		privateKey,
+	        byte[]						subjectKeyID,
+	        string						digestOID,
+	        CmsAttributeTableGenerator	signedAttrGen,
+	        CmsAttributeTableGenerator	unsignedAttrGen)
+	    {
+			AddSigner(privateKey, subjectKeyID, GetEncOid(privateKey, digestOID), digestOID,
+				signedAttrGen, unsignedAttrGen);
+	    }
+
+		/**
+		 * add a signer, including digest encryption algorithm, with extra signed/unsigned attributes based on generators.
+		 */
+		public void AddSigner(
+			AsymmetricKeyParameter		privateKey,
+			byte[]						subjectKeyID,
+			string						encryptionOID,
+			string						digestOID,
+			CmsAttributeTableGenerator	signedAttrGen,
+			CmsAttributeTableGenerator	unsignedAttrGen)
+		{
+			doAddSigner(privateKey, GetSignerIdentifier(subjectKeyID), encryptionOID, digestOID,
+				signedAttrGen, unsignedAttrGen, null);
+		}
+
+		private void doAddSigner(
+			AsymmetricKeyParameter		privateKey,
+			SignerIdentifier            signerIdentifier,
+			string                      encryptionOID,
+			string                      digestOID,
+			CmsAttributeTableGenerator  signedAttrGen,
+			CmsAttributeTableGenerator  unsignedAttrGen,
+			Asn1.Cms.AttributeTable		baseSignedTable)
+		{
+			signerInfs.Add(new SignerInf(this, privateKey, signerIdentifier, digestOID, encryptionOID,
+				signedAttrGen, unsignedAttrGen, baseSignedTable));
+		}
+
+		/**
+        * generate a signed object that for a CMS Signed Data object
+        */
+        public CmsSignedData Generate(
+            CmsProcessable content)
+        {
+            return Generate(content, false);
+        }
+
+        /**
+        * generate a signed object that for a CMS Signed Data
+        * object  - if encapsulate is true a copy
+        * of the message will be included in the signature. The content type
+        * is set according to the OID represented by the string signedContentType.
+        */
+        public CmsSignedData Generate(
+            string			signedContentType,
+			// FIXME Avoid accessing more than once to support CmsProcessableInputStream
+            CmsProcessable	content,
+            bool			encapsulate)
+        {
+            Asn1EncodableVector digestAlgs = new Asn1EncodableVector();
+            Asn1EncodableVector signerInfos = new Asn1EncodableVector();
+
+			_digests.Clear(); // clear the current preserved digest state
+
+			//
+            // add the precalculated SignerInfo objects.
+            //
+            foreach (SignerInformation signer in _signers)
+            {
+				digestAlgs.Add(Helper.FixAlgID(signer.DigestAlgorithmID));
+
+				// TODO Verify the content type and calculated digest match the precalculated SignerInfo
+				signerInfos.Add(signer.ToSignerInfo());
+            }
+
+			//
+            // add the SignerInfo objects
+            //
+            bool isCounterSignature = (signedContentType == null);
+
+            DerObjectIdentifier contentTypeOid = isCounterSignature
+                ?   null
+				:	new DerObjectIdentifier(signedContentType);
+
+            foreach (SignerInf signer in signerInfs)
+            {
+				try
+                {
+					digestAlgs.Add(signer.DigestAlgorithmID);
+                    signerInfos.Add(signer.ToSignerInfo(contentTypeOid, content, rand));
+				}
+                catch (IOException e)
+                {
+                    throw new CmsException("encoding error.", e);
+                }
+                catch (InvalidKeyException e)
+                {
+                    throw new CmsException("key inappropriate for signature.", e);
+                }
+                catch (SignatureException e)
+                {
+                    throw new CmsException("error creating signature.", e);
+                }
+                catch (CertificateEncodingException e)
+                {
+                    throw new CmsException("error creating sid.", e);
+                }
+            }
+
+			Asn1Set certificates = null;
+
+			if (_certs.Count != 0)
+			{
+				certificates = CmsUtilities.CreateBerSetFromList(_certs);
+			}
+
+			Asn1Set certrevlist = null;
+
+			if (_crls.Count != 0)
+			{
+				certrevlist = CmsUtilities.CreateBerSetFromList(_crls);
+			}
+
+			Asn1OctetString octs = null;
+			if (encapsulate)
+            {
+                MemoryStream bOut = new MemoryStream();
+				if (content != null)
+				{
+	                try
+	                {
+	                    content.Write(bOut);
+	                }
+	                catch (IOException e)
+	                {
+	                    throw new CmsException("encapsulation error.", e);
+	                }
+				}
+				octs = new BerOctetString(bOut.ToArray());
+            }
+
+            ContentInfo encInfo = new ContentInfo(contentTypeOid, octs);
+
+            SignedData sd = new SignedData(
+                new DerSet(digestAlgs),
+                encInfo,
+                certificates,
+                certrevlist,
+                new DerSet(signerInfos));
+
+            ContentInfo contentInfo = new ContentInfo(CmsObjectIdentifiers.SignedData, sd);
+
+            return new CmsSignedData(content, contentInfo);
+        }
+
+        /**
+        * generate a signed object that for a CMS Signed Data
+        * object - if encapsulate is true a copy
+        * of the message will be included in the signature with the
+        * default content type "data".
+        */
+        public CmsSignedData Generate(
+            CmsProcessable	content,
+            bool			encapsulate)
+        {
+            return this.Generate(Data, content, encapsulate);
+        }
+
+		/**
+		* generate a set of one or more SignerInformation objects representing counter signatures on
+		* the passed in SignerInformation object.
+		*
+		* @param signer the signer to be countersigned
+		* @param sigProvider the provider to be used for counter signing.
+		* @return a store containing the signers.
+		*/
+		public SignerInformationStore GenerateCounterSigners(
+			SignerInformation signer)
+		{
+			return this.Generate(null, new CmsProcessableByteArray(signer.GetSignature()), false).GetSignerInfos();
+		}
+	}
+}
diff --git a/Crypto/src/cms/CMSSignedDataParser.cs b/Crypto/src/cms/CMSSignedDataParser.cs
new file mode 100644
index 000000000..dd794ee77
--- /dev/null
+++ b/Crypto/src/cms/CMSSignedDataParser.cs
@@ -0,0 +1,455 @@
+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.Security;
+using Org.BouncyCastle.Security.Certificates;
+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
+{
+	/**
+	* Parsing class for an CMS Signed Data object from an input stream.
+	* <p>
+	* Note: that because we are in a streaming mode only one signer can be tried and it is important
+	* that the methods on the parser are called in the appropriate order.
+	* </p>
+	* <p>
+	* A simple example of usage for an encapsulated signature.
+	* </p>
+	* <p>
+	* Two notes: first, in the example below the validity of
+	* the certificate isn't verified, just the fact that one of the certs
+	* matches the given signer, and, second, because we are in a streaming
+	* mode the order of the operations is important.
+	* </p>
+	* <pre>
+	*      CmsSignedDataParser     sp = new CmsSignedDataParser(encapSigData);
+	*
+	*      sp.GetSignedContent().Drain();
+	*
+	*      IX509Store              certs = sp.GetCertificates();
+	*      SignerInformationStore  signers = sp.GetSignerInfos();
+	*
+	*      foreach (SignerInformation signer in signers.GetSigners())
+	*      {
+	*          ArrayList       certList = new ArrayList(certs.GetMatches(signer.SignerID));
+	*          X509Certificate cert = (X509Certificate) certList[0];
+	*
+	*          Console.WriteLine("verify returns: " + signer.Verify(cert));
+	*      }
+	* </pre>
+	*  Note also: this class does not introduce buffering - if you are processing large files you should create
+	*  the parser with:
+	*  <pre>
+	*          CmsSignedDataParser     ep = new CmsSignedDataParser(new BufferedInputStream(encapSigData, bufSize));
+	*  </pre>
+	*  where bufSize is a suitably large buffer size.
+	*/
+	public class CmsSignedDataParser
+		: CmsContentInfoParser
+	{
+		private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
+
+		private SignedDataParser        _signedData;
+		private DerObjectIdentifier		_signedContentType;
+		private CmsTypedStream          _signedContent;
+		private IDictionary				_digests;
+		private ISet					_digestOids;
+
+		private SignerInformationStore  _signerInfoStore;
+		private Asn1Set                 _certSet, _crlSet;
+		private bool					_isCertCrlParsed;
+		private IX509Store				_attributeStore;
+		private IX509Store				_certificateStore;
+		private IX509Store				_crlStore;
+
+		public CmsSignedDataParser(
+			byte[] sigBlock)
+			: this(new MemoryStream(sigBlock, false))
+		{
+		}
+
+		public CmsSignedDataParser(
+			CmsTypedStream	signedContent,
+			byte[]			sigBlock)
+			: this(signedContent, new MemoryStream(sigBlock, false))
+		{
+		}
+
+		/**
+		* base constructor - with encapsulated content
+		*/
+		public CmsSignedDataParser(
+			Stream sigData)
+			: this(null, sigData)
+		{
+		}
+
+		/**
+		* base constructor
+		*
+		* @param signedContent the content that was signed.
+		* @param sigData the signature object.
+		*/
+		public CmsSignedDataParser(
+			CmsTypedStream	signedContent,
+			Stream			sigData)
+			: base(sigData)
+		{
+			try
+			{
+				this._signedContent = signedContent;
+				this._signedData = SignedDataParser.GetInstance(this.contentInfo.GetContent(Asn1Tags.Sequence));
+				this._digests = Platform.CreateHashtable();
+				this._digestOids = new HashSet();
+
+				Asn1SetParser digAlgs = _signedData.GetDigestAlgorithms();
+				IAsn1Convertible o;
+
+				while ((o = digAlgs.ReadObject()) != null)
+				{
+					AlgorithmIdentifier id = AlgorithmIdentifier.GetInstance(o.ToAsn1Object());
+
+					try
+					{
+						string digestOid = id.ObjectID.Id;
+						string digestName = Helper.GetDigestAlgName(digestOid);
+
+						if (!this._digests.Contains(digestName))
+						{
+							this._digests[digestName] = Helper.GetDigestInstance(digestName);
+							this._digestOids.Add(digestOid);
+						}
+					}
+					catch (SecurityUtilityException)
+					{
+						// TODO Should do something other than ignore it
+					}
+				}
+
+				//
+				// If the message is simply a certificate chain message GetContent() may return null.
+				//
+				ContentInfoParser cont = _signedData.GetEncapContentInfo();
+				Asn1OctetStringParser octs = (Asn1OctetStringParser)
+					cont.GetContent(Asn1Tags.OctetString);
+
+				if (octs != null)
+				{
+					CmsTypedStream ctStr = new CmsTypedStream(
+						cont.ContentType.Id, octs.GetOctetStream());
+
+					if (_signedContent == null)
+					{
+						this._signedContent = ctStr;
+					}
+					else
+					{
+						//
+						// content passed in, need to read past empty encapsulated content info object if present
+						//
+						ctStr.Drain();
+					}
+				}
+
+				_signedContentType = _signedContent == null
+					?	cont.ContentType
+					:	new DerObjectIdentifier(_signedContent.ContentType);
+			}
+			catch (IOException e)
+			{
+				throw new CmsException("io exception: " + e.Message, e);
+			}
+
+			if (_digests.Count < 1)
+			{
+				throw new CmsException("no digests could be created for message.");
+			}
+		}
+
+		/**
+		 * Return the version number for the SignedData object
+		 *
+		 * @return the version number
+		 */
+		public int Version
+		{
+			get { return _signedData.Version.Value.IntValue; }
+		}
+
+		public ISet DigestOids
+		{
+			get { return new HashSet(_digestOids); }
+		}
+
+		/**
+		* return the collection of signers that are associated with the
+		* signatures for the message.
+		* @throws CmsException
+		*/
+		public SignerInformationStore GetSignerInfos()
+		{
+			if (_signerInfoStore == null)
+			{
+				PopulateCertCrlSets();
+
+                IList signerInfos = Platform.CreateArrayList();
+                IDictionary hashes = Platform.CreateHashtable();
+
+				foreach (object digestKey in _digests.Keys)
+				{
+					hashes[digestKey] = DigestUtilities.DoFinal(
+						(IDigest)_digests[digestKey]);
+				}
+
+				try
+				{
+					Asn1SetParser s = _signedData.GetSignerInfos();
+					IAsn1Convertible o;
+
+					while ((o = s.ReadObject()) != null)
+					{
+						SignerInfo info = SignerInfo.GetInstance(o.ToAsn1Object());
+						string digestName = Helper.GetDigestAlgName(
+							info.DigestAlgorithm.ObjectID.Id);
+
+						byte[] hash = (byte[]) hashes[digestName];
+
+						signerInfos.Add(new SignerInformation(info, _signedContentType, null, new BaseDigestCalculator(hash)));
+					}
+				}
+				catch (IOException e)
+				{
+					throw new CmsException("io exception: " + e.Message, e);
+				}
+
+				_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 org.bouncycastle.x509.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 (_attributeStore == null)
+			{
+				PopulateCertCrlSets();
+
+				_attributeStore = Helper.CreateAttributeStore(type, _certSet);
+			}
+
+			return _attributeStore;
+		}
+
+		/**
+		* 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)
+			{
+				PopulateCertCrlSets();
+
+				_certificateStore = Helper.CreateCertificateStore(type, _certSet);
+			}
+
+			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)
+			{
+				PopulateCertCrlSets();
+
+				_crlStore = Helper.CreateCrlStore(type, _crlSet);
+			}
+
+			return _crlStore;
+		}
+
+		private void PopulateCertCrlSets()
+		{
+			if (_isCertCrlParsed)
+				return;
+
+			_isCertCrlParsed = true;
+
+			try
+			{
+				// care! Streaming - Must process the GetCertificates() result before calling GetCrls()
+				_certSet = GetAsn1Set(_signedData.GetCertificates());
+				_crlSet = GetAsn1Set(_signedData.GetCrls());
+			}
+			catch (IOException e)
+			{
+				throw new CmsException("problem parsing cert/crl sets", e);
+			}
+		}
+
+		/// <summary>
+		/// Return the <c>DerObjectIdentifier</c> associated with the encapsulated
+		/// content info structure carried in the signed data.
+		/// </summary>
+		public DerObjectIdentifier SignedContentType
+		{
+			get { return _signedContentType; }
+		}
+
+		public CmsTypedStream GetSignedContent()
+		{
+			if (_signedContent == null)
+			{
+				return null;
+			}
+
+			Stream digStream = _signedContent.ContentStream;
+
+			foreach (IDigest digest in _digests.Values)
+			{
+				digStream = new DigestStream(digStream, digest, null);
+			}
+
+			return new CmsTypedStream(_signedContent.ContentType, digStream);
+		}
+
+		/**
+		 * Replace the signerinformation store associated with the passed
+		 * in message contained in the stream original 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.
+		 * <p>
+		 * The output stream is returned unclosed.
+		 * </p>
+		 * @param original the signed data stream to be used as a base.
+		 * @param signerInformationStore the new signer information store to use.
+		 * @param out the stream to Write the new signed data object to.
+		 * @return out.
+		 */
+		public static Stream ReplaceSigners(
+			Stream					original,
+			SignerInformationStore	signerInformationStore,
+			Stream					outStr)
+		{
+			// NB: SecureRandom would be ignored since using existing signatures only
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+			CmsSignedDataParser parser = new CmsSignedDataParser(original);
+
+//			gen.AddDigests(parser.DigestOids);
+			gen.AddSigners(signerInformationStore);
+
+			CmsTypedStream signedContent = parser.GetSignedContent();
+			bool encapsulate = (signedContent != null);
+			Stream contentOut = gen.Open(outStr, parser.SignedContentType.Id, encapsulate);
+			if (encapsulate)
+			{
+				Streams.PipeAll(signedContent.ContentStream, contentOut);
+			}
+
+			gen.AddAttributeCertificates(parser.GetAttributeCertificates("Collection"));
+			gen.AddCertificates(parser.GetCertificates("Collection"));
+			gen.AddCrls(parser.GetCrls("Collection"));
+
+//			gen.AddSigners(parser.GetSignerInfos());
+
+            contentOut.Dispose();
+
+			return outStr;
+		}
+
+		/**
+		 * Replace the certificate and CRL information associated with this
+		 * CMSSignedData object with the new one passed in.
+		 * <p>
+		 * The output stream is returned unclosed.
+		 * </p>
+		 * @param original the signed data stream to be used as a base.
+		 * @param certsAndCrls the new certificates and CRLs to be used.
+		 * @param out the stream to Write the new signed data object to.
+		 * @return out.
+		 * @exception CmsException if there is an error processing the CertStore
+		 */
+		public static Stream ReplaceCertificatesAndCrls(
+			Stream			original,
+			IX509Store		x509Certs,
+			IX509Store		x509Crls,
+			IX509Store		x509AttrCerts,
+			Stream			outStr)
+		{
+			// NB: SecureRandom would be ignored since using existing signatures only
+			CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+			CmsSignedDataParser parser = new CmsSignedDataParser(original);
+
+			gen.AddDigests(parser.DigestOids);
+
+			CmsTypedStream signedContent = parser.GetSignedContent();
+			bool encapsulate = (signedContent != null);
+			Stream contentOut = gen.Open(outStr, parser.SignedContentType.Id, encapsulate);
+			if (encapsulate)
+			{
+				Streams.PipeAll(signedContent.ContentStream, contentOut);
+			}
+
+//			gen.AddAttributeCertificates(parser.GetAttributeCertificates("Collection"));
+//			gen.AddCertificates(parser.GetCertificates("Collection"));
+//			gen.AddCrls(parser.GetCrls("Collection"));
+			if (x509AttrCerts != null)
+				gen.AddAttributeCertificates(x509AttrCerts);
+			if (x509Certs != null)
+				gen.AddCertificates(x509Certs);
+			if (x509Crls != null)
+				gen.AddCrls(x509Crls);
+
+			gen.AddSigners(parser.GetSignerInfos());
+
+            contentOut.Dispose();
+
+			return outStr;
+		}
+
+		private static Asn1Set GetAsn1Set(
+			Asn1SetParser asn1SetParser)
+		{
+			return asn1SetParser == null
+				?	null
+				:	Asn1Set.GetInstance(asn1SetParser.ToAsn1Object());
+		}
+	}
+}
diff --git a/Crypto/src/cms/CMSSignedDataStreamGenerator.cs b/Crypto/src/cms/CMSSignedDataStreamGenerator.cs
new file mode 100644
index 000000000..0bed9fcad
--- /dev/null
+++ b/Crypto/src/cms/CMSSignedDataStreamGenerator.cs
@@ -0,0 +1,917 @@
+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.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.IO;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Cms
+{
+    /**
+    * General class for generating a pkcs7-signature message stream.
+    * <p>
+    * A simple example of usage.
+    * </p>
+    * <pre>
+    *      IX509Store                   certs...
+    *      CmsSignedDataStreamGenerator gen = new CmsSignedDataStreamGenerator();
+    *
+    *      gen.AddSigner(privateKey, cert, CmsSignedDataStreamGenerator.DIGEST_SHA1);
+    *
+    *      gen.AddCertificates(certs);
+    *
+    *      Stream sigOut = gen.Open(bOut);
+    *
+    *      sigOut.Write(Encoding.UTF8.GetBytes("Hello World!"));
+    *
+    *      sigOut.Close();
+    * </pre>
+    */
+    public class CmsSignedDataStreamGenerator
+        : CmsSignedGenerator
+    {
+		private static readonly CmsSignedHelper Helper = CmsSignedHelper.Instance;
+
+		private readonly IList      _signerInfs = Platform.CreateArrayList();
+		private readonly ISet		_messageDigestOids = new HashSet();
+        private readonly IDictionary _messageDigests = Platform.CreateHashtable();
+        private readonly IDictionary _messageHashes = Platform.CreateHashtable();
+		private bool				_messageDigestsLocked;
+        private int					_bufferSize;
+
+		private class DigestAndSignerInfoGeneratorHolder
+		{
+			internal readonly SignerInfoGenerator	signerInf;
+			internal readonly string				digestOID;
+
+			internal DigestAndSignerInfoGeneratorHolder(SignerInfoGenerator signerInf, String digestOID)
+			{
+				this.signerInf = signerInf;
+				this.digestOID = digestOID;
+			}
+
+			internal AlgorithmIdentifier DigestAlgorithm
+			{
+				get { return new AlgorithmIdentifier(new DerObjectIdentifier(this.digestOID), DerNull.Instance); }
+			}
+		}
+
+		private class SignerInfoGeneratorImpl : SignerInfoGenerator
+        {
+			private readonly CmsSignedDataStreamGenerator outer;
+
+			private readonly SignerIdentifier			_signerIdentifier;
+			private readonly string						_digestOID;
+			private readonly string						_encOID;
+			private readonly CmsAttributeTableGenerator	_sAttr;
+			private readonly CmsAttributeTableGenerator	_unsAttr;
+			private readonly string						_encName;
+			private readonly ISigner					_sig;
+
+			internal SignerInfoGeneratorImpl(
+				CmsSignedDataStreamGenerator	outer,
+				AsymmetricKeyParameter			key,
+				SignerIdentifier				signerIdentifier,
+				string							digestOID,
+				string							encOID,
+				CmsAttributeTableGenerator		sAttr,
+				CmsAttributeTableGenerator		unsAttr)
+			{
+				this.outer = outer;
+
+				_signerIdentifier = signerIdentifier;
+				_digestOID = digestOID;
+				_encOID = encOID;
+				_sAttr = sAttr;
+				_unsAttr = unsAttr;
+				_encName = Helper.GetEncryptionAlgName(_encOID);
+
+				string digestName = Helper.GetDigestAlgName(_digestOID);
+				string signatureName = digestName + "with" + _encName;
+
+				if (_sAttr != null)
+				{
+            		_sig = Helper.GetSignatureInstance(signatureName);
+				}
+				else
+				{
+					// Note: Need to use raw signatures here since we have already calculated the digest
+					if (_encName.Equals("RSA"))
+					{
+						_sig = Helper.GetSignatureInstance("RSA");
+					}
+					else if (_encName.Equals("DSA"))
+					{
+						_sig = Helper.GetSignatureInstance("NONEwithDSA");
+					}
+					// TODO Add support for raw PSS
+//					else if (_encName.equals("RSAandMGF1"))
+//					{
+//						_sig = CMSSignedHelper.INSTANCE.getSignatureInstance("NONEWITHRSAPSS", _sigProvider);
+//						try
+//						{
+//							// Init the params this way to avoid having a 'raw' version of each PSS algorithm
+//							Signature sig2 = CMSSignedHelper.INSTANCE.getSignatureInstance(signatureName, _sigProvider);
+//							PSSParameterSpec spec = (PSSParameterSpec)sig2.getParameters().getParameterSpec(PSSParameterSpec.class);
+//							_sig.setParameter(spec);
+//						}
+//						catch (Exception e)
+//						{
+//							throw new SignatureException("algorithm: " + _encName + " could not be configured.");
+//						}
+//					}
+					else
+					{
+						throw new SignatureException("algorithm: " + _encName + " not supported in base signatures.");
+					}
+				}
+
+				_sig.Init(true, new ParametersWithRandom(key, outer.rand));
+			}
+
+			public SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm,
+        		byte[] calculatedDigest)
+			{
+				try
+				{
+					string digestName = Helper.GetDigestAlgName(_digestOID);
+					string signatureName = digestName + "with" + _encName;
+
+//					AlgorithmIdentifier digAlgId = DigestAlgorithmID;
+//
+//					byte[] hash = (byte[])outer._messageHashes[Helper.GetDigestAlgName(this._digestOID)];
+//					outer._digests[_digestOID] = hash.Clone();
+
+					byte[] bytesToSign = calculatedDigest;
+
+					/* RFC 3852 5.4
+					 * The result of the message digest calculation process depends on
+					 * whether the signedAttrs field is present.  When the field is absent,
+					 * the result is just the message digest of the content as described
+					 *
+					 * above.  When the field is present, however, the result is the message
+					 * digest of the complete DER encoding of the SignedAttrs value
+					 * contained in the signedAttrs field.
+					 */
+					Asn1Set signedAttr = null;
+					if (_sAttr != null)
+					{
+						IDictionary parameters = outer.GetBaseParameters(contentType, digestAlgorithm, calculatedDigest);
+
+//						Asn1.Cms.AttributeTable signed = _sAttr.GetAttributes(Collections.unmodifiableMap(parameters));
+						Asn1.Cms.AttributeTable signed = _sAttr.GetAttributes(parameters);
+
+                        if (contentType == null) //counter signature
+                        {
+                            if (signed != null && signed[CmsAttributes.ContentType] != null)
+                            {
+                                IDictionary tmpSigned = signed.ToDictionary();
+                                tmpSigned.Remove(CmsAttributes.ContentType);
+                                signed = new Asn1.Cms.AttributeTable(tmpSigned);
+                            }
+                        }
+
+                        signedAttr = outer.GetAttributeSet(signed);
+
+                		// sig must be composed from the DER encoding.
+						bytesToSign = signedAttr.GetEncoded(Asn1Encodable.Der);
+					}
+					else
+					{
+						// Note: Need to use raw signatures here since we have already calculated the digest
+						if (_encName.Equals("RSA"))
+						{
+							DigestInfo dInfo = new DigestInfo(digestAlgorithm, calculatedDigest);
+							bytesToSign = dInfo.GetEncoded(Asn1Encodable.Der);
+						}
+					}
+
+					_sig.BlockUpdate(bytesToSign, 0, bytesToSign.Length);
+					byte[] sigBytes = _sig.GenerateSignature();
+
+					Asn1Set unsignedAttr = null;
+					if (_unsAttr != null)
+					{
+						IDictionary parameters = outer.GetBaseParameters(
+							contentType, digestAlgorithm, calculatedDigest);
+						parameters[CmsAttributeTableParameter.Signature] = sigBytes.Clone();
+
+//						Asn1.Cms.AttributeTable unsigned = _unsAttr.getAttributes(Collections.unmodifiableMap(parameters));
+						Asn1.Cms.AttributeTable unsigned = _unsAttr.GetAttributes(parameters);
+
+						unsignedAttr = outer.GetAttributeSet(unsigned);
+					}
+
+					// TODO[RSAPSS] Need the ability to specify non-default parameters
+					Asn1Encodable sigX509Parameters = SignerUtilities.GetDefaultX509Parameters(signatureName);
+					AlgorithmIdentifier digestEncryptionAlgorithm = CmsSignedGenerator.GetEncAlgorithmIdentifier(
+						new DerObjectIdentifier(_encOID), sigX509Parameters);
+
+					return new SignerInfo(_signerIdentifier, digestAlgorithm,
+						signedAttr, digestEncryptionAlgorithm, new DerOctetString(sigBytes), unsignedAttr);
+				}
+	            catch (IOException e)
+	            {
+	                throw new CmsStreamException("encoding error.", e);
+	            }
+	            catch (SignatureException e)
+	            {
+	                throw new CmsStreamException("error creating signature.", e);
+	            }
+            }
+        }
+
+		public CmsSignedDataStreamGenerator()
+        {
+        }
+
+		/// <summary>Constructor allowing specific source of randomness</summary>
+		/// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
+		public CmsSignedDataStreamGenerator(
+			SecureRandom rand)
+			: base(rand)
+		{
+		}
+
+		/**
+        * Set the underlying string size for encapsulated data
+        *
+        * @param bufferSize length of octet strings to buffer the data.
+        */
+        public void SetBufferSize(
+            int bufferSize)
+        {
+            _bufferSize = bufferSize;
+        }
+
+		public void AddDigests(
+       		params string[] digestOids)
+		{
+       		AddDigests((IEnumerable) digestOids);
+		}
+
+		public void AddDigests(
+			IEnumerable digestOids)
+		{
+			foreach (string digestOid in digestOids)
+			{
+				ConfigureDigest(digestOid);
+			}
+		}
+
+		/**
+        * add a signer - no attributes other than the default ones will be
+        * provided here.
+        * @throws NoSuchAlgorithmException
+        * @throws InvalidKeyException
+        */
+        public void AddSigner(
+            AsymmetricKeyParameter	privateKey,
+            X509Certificate			cert,
+            string					digestOid)
+        {
+			AddSigner(privateKey, cert, digestOid,
+				new DefaultSignedAttributeTableGenerator(), null);
+		}
+
+		/**
+		 * add a signer, specifying the digest encryption algorithm - no attributes other than the default ones will be
+		 * provided here.
+		 * @throws NoSuchProviderException
+		 * @throws NoSuchAlgorithmException
+		 * @throws InvalidKeyException
+		 */
+		public void AddSigner(
+			AsymmetricKeyParameter	privateKey,
+			X509Certificate			cert,
+			string					encryptionOid,
+			string					digestOid)
+		{
+			AddSigner(privateKey, cert, encryptionOid, digestOid,
+				new DefaultSignedAttributeTableGenerator(),
+				(CmsAttributeTableGenerator)null);
+		}
+
+        /**
+        * add a signer with extra signed/unsigned attributes.
+        * @throws NoSuchAlgorithmException
+        * @throws InvalidKeyException
+        */
+        public void AddSigner(
+            AsymmetricKeyParameter	privateKey,
+            X509Certificate			cert,
+            string					digestOid,
+            Asn1.Cms.AttributeTable	signedAttr,
+            Asn1.Cms.AttributeTable	unsignedAttr)
+        {
+			AddSigner(privateKey, cert, digestOid,
+				new DefaultSignedAttributeTableGenerator(signedAttr),
+				new SimpleAttributeTableGenerator(unsignedAttr));
+		}
+
+		/**
+		 * add a signer with extra signed/unsigned attributes - specifying digest
+		 * encryption algorithm.
+		 * @throws NoSuchProviderException
+		 * @throws NoSuchAlgorithmException
+		 * @throws InvalidKeyException
+		 */
+		public void AddSigner(
+			AsymmetricKeyParameter	privateKey,
+			X509Certificate			cert,
+			string					encryptionOid,
+			string					digestOid,
+			Asn1.Cms.AttributeTable	signedAttr,
+			Asn1.Cms.AttributeTable	unsignedAttr)
+		{
+			AddSigner(privateKey, cert, encryptionOid, digestOid,
+				new DefaultSignedAttributeTableGenerator(signedAttr),
+				new SimpleAttributeTableGenerator(unsignedAttr));
+		}
+
+		public void AddSigner(
+			AsymmetricKeyParameter		privateKey,
+			X509Certificate				cert,
+			string						digestOid,
+			CmsAttributeTableGenerator  signedAttrGenerator,
+			CmsAttributeTableGenerator  unsignedAttrGenerator)
+		{
+			AddSigner(privateKey, cert, GetEncOid(privateKey, digestOid), digestOid,
+				signedAttrGenerator, unsignedAttrGenerator);
+        }
+
+		public void AddSigner(
+			AsymmetricKeyParameter		privateKey,
+			X509Certificate				cert,
+			string						encryptionOid,
+			string						digestOid,
+			CmsAttributeTableGenerator  signedAttrGenerator,
+			CmsAttributeTableGenerator  unsignedAttrGenerator)
+		{
+			DoAddSigner(privateKey, GetSignerIdentifier(cert), encryptionOid, digestOid,
+				signedAttrGenerator, unsignedAttrGenerator);
+		}
+
+		/**
+		* add a signer - no attributes other than the default ones will be
+		* provided here.
+		* @throws NoSuchAlgorithmException
+		* @throws InvalidKeyException
+		*/
+		public void AddSigner(
+			AsymmetricKeyParameter	privateKey,
+			byte[]					subjectKeyID,
+			string					digestOid)
+		{
+			AddSigner(privateKey, subjectKeyID, digestOid, new DefaultSignedAttributeTableGenerator(),
+				(CmsAttributeTableGenerator)null);
+		}
+
+		/**
+		 * add a signer - no attributes other than the default ones will be
+		 * provided here.
+		 * @throws NoSuchProviderException
+		 * @throws NoSuchAlgorithmException
+		 * @throws InvalidKeyException
+		 */
+		public void AddSigner(
+			AsymmetricKeyParameter	privateKey,
+			byte[]					subjectKeyID,
+			string					encryptionOid,
+			string					digestOid)
+		{
+			AddSigner(privateKey, subjectKeyID, encryptionOid, digestOid,
+				new DefaultSignedAttributeTableGenerator(),
+				(CmsAttributeTableGenerator)null);
+		}
+
+		/**
+		* add a signer with extra signed/unsigned attributes.
+		* @throws NoSuchAlgorithmException
+		* @throws InvalidKeyException
+		*/
+		public void AddSigner(
+			AsymmetricKeyParameter	privateKey,
+			byte[]					subjectKeyID,
+			string					digestOid,
+			Asn1.Cms.AttributeTable	signedAttr,
+			Asn1.Cms.AttributeTable	unsignedAttr)
+	    {
+	        AddSigner(privateKey, subjectKeyID, digestOid,
+				new DefaultSignedAttributeTableGenerator(signedAttr),
+				new SimpleAttributeTableGenerator(unsignedAttr));
+		}
+
+		public void AddSigner(
+			AsymmetricKeyParameter		privateKey,
+			byte[]						subjectKeyID,
+			string						digestOid,
+			CmsAttributeTableGenerator	signedAttrGenerator,
+			CmsAttributeTableGenerator	unsignedAttrGenerator)
+		{
+			AddSigner(privateKey, subjectKeyID, GetEncOid(privateKey, digestOid),
+				digestOid, signedAttrGenerator, unsignedAttrGenerator);
+		}
+
+		public void AddSigner(
+			AsymmetricKeyParameter		privateKey,
+			byte[]						subjectKeyID,
+			string						encryptionOid,
+			string						digestOid,
+			CmsAttributeTableGenerator	signedAttrGenerator,
+			CmsAttributeTableGenerator	unsignedAttrGenerator)
+		{
+			DoAddSigner(privateKey, GetSignerIdentifier(subjectKeyID), encryptionOid, digestOid,
+				signedAttrGenerator, unsignedAttrGenerator);
+		}
+
+		private void DoAddSigner(
+			AsymmetricKeyParameter		privateKey,
+			SignerIdentifier			signerIdentifier,
+			string						encryptionOid,
+			string						digestOid,
+			CmsAttributeTableGenerator	signedAttrGenerator,
+			CmsAttributeTableGenerator	unsignedAttrGenerator)
+		{
+			ConfigureDigest(digestOid);
+
+			SignerInfoGeneratorImpl signerInf = new SignerInfoGeneratorImpl(this, privateKey,
+				signerIdentifier, digestOid, encryptionOid, signedAttrGenerator, unsignedAttrGenerator);
+
+			_signerInfs.Add(new DigestAndSignerInfoGeneratorHolder(signerInf, digestOid));
+		}
+
+		internal override void AddSignerCallback(
+			SignerInformation si)
+		{
+			// FIXME If there were parameters in si.DigestAlgorithmID.Parameters, they are lost
+			// NB: Would need to call FixAlgID on the DigestAlgorithmID
+
+			// For precalculated signers, just need to register the algorithm, not configure a digest
+			RegisterDigestOid(si.DigestAlgorithmID.ObjectID.Id);
+		}
+
+		/**
+        * generate a signed object that for a CMS Signed Data object
+        */
+        public Stream Open(
+            Stream outStream)
+        {
+            return Open(outStream, false);
+        }
+
+        /**
+        * generate a signed object that for a CMS Signed Data
+        * object - if encapsulate is true a copy
+        * of the message will be included in the signature with the
+        * default content type "data".
+        */
+        public Stream Open(
+            Stream	outStream,
+            bool	encapsulate)
+        {
+            return Open(outStream, Data, encapsulate);
+        }
+
+		/**
+		 * generate a signed object that for a CMS Signed Data
+		 * object using the given provider - if encapsulate is true a copy
+		 * of the message will be included in the signature with the
+		 * default content type "data". If dataOutputStream is non null the data
+		 * being signed will be written to the stream as it is processed.
+		 * @param out stream the CMS object is to be written to.
+		 * @param encapsulate true if data should be encapsulated.
+		 * @param dataOutputStream output stream to copy the data being signed to.
+		 */
+		public Stream Open(
+			Stream	outStream,
+			bool	encapsulate,
+			Stream	dataOutputStream)
+		{
+			return Open(outStream, Data, encapsulate, dataOutputStream);
+		}
+
+		/**
+        * generate a signed object that for a CMS Signed Data
+        * object - if encapsulate is true a copy
+        * of the message will be included in the signature. The content type
+        * is set according to the OID represented by the string signedContentType.
+        */
+        public Stream Open(
+            Stream	outStream,
+            string	signedContentType,
+            bool	encapsulate)
+        {
+			return Open(outStream, signedContentType, encapsulate, null);
+		}
+
+		/**
+		* generate a signed object that for a CMS Signed Data
+		* object using the given provider - if encapsulate is true a copy
+		* of the message will be included in the signature. The content type
+		* is set according to the OID represented by the string signedContentType.
+		* @param out stream the CMS object is to be written to.
+		* @param signedContentType OID for data to be signed.
+		* @param encapsulate true if data should be encapsulated.
+		* @param dataOutputStream output stream to copy the data being signed to.
+		*/
+		public Stream Open(
+			Stream	outStream,
+			string	signedContentType,
+			bool	encapsulate,
+			Stream	dataOutputStream)
+		{
+			if (outStream == null)
+				throw new ArgumentNullException("outStream");
+			if (!outStream.CanWrite)
+				throw new ArgumentException("Expected writeable stream", "outStream");
+			if (dataOutputStream != null && !dataOutputStream.CanWrite)
+				throw new ArgumentException("Expected writeable stream", "dataOutputStream");
+
+			_messageDigestsLocked = true;
+
+			//
+            // ContentInfo
+            //
+            BerSequenceGenerator sGen = new BerSequenceGenerator(outStream);
+
+			sGen.AddObject(CmsObjectIdentifiers.SignedData);
+
+			//
+            // Signed Data
+            //
+            BerSequenceGenerator sigGen = new BerSequenceGenerator(
+				sGen.GetRawOutputStream(), 0, true);
+
+            bool isCounterSignature = (signedContentType == null);
+
+            DerObjectIdentifier contentTypeOid = isCounterSignature
+                ? null
+                : new DerObjectIdentifier(signedContentType);
+
+            sigGen.AddObject(CalculateVersion(contentTypeOid));
+
+			Asn1EncodableVector digestAlgs = new Asn1EncodableVector();
+
+			foreach (string digestOid in _messageDigestOids)
+            {
+				digestAlgs.Add(
+            		new AlgorithmIdentifier(new DerObjectIdentifier(digestOid), DerNull.Instance));
+            }
+
+            {
+				byte[] tmp = new DerSet(digestAlgs).GetEncoded();
+				sigGen.GetRawOutputStream().Write(tmp, 0, tmp.Length);
+			}
+
+			BerSequenceGenerator eiGen = new BerSequenceGenerator(sigGen.GetRawOutputStream());
+            eiGen.AddObject(contentTypeOid);
+
+        	// If encapsulating, add the data as an octet string in the sequence
+			Stream encapStream = encapsulate
+				?	CmsUtilities.CreateBerOctetOutputStream(eiGen.GetRawOutputStream(), 0, true, _bufferSize)
+				:	null;
+
+        	// Also send the data to 'dataOutputStream' if necessary
+			Stream teeStream = GetSafeTeeOutputStream(dataOutputStream, encapStream);
+
+        	// Let all the digests see the data as it is written
+			Stream digStream = AttachDigestsToOutputStream(_messageDigests.Values, teeStream);
+
+			return new CmsSignedDataOutputStream(this, digStream, signedContentType, sGen, sigGen, eiGen);
+        }
+
+		private void RegisterDigestOid(
+			string digestOid)
+		{
+       		if (_messageDigestsLocked)
+       		{
+       			if (!_messageDigestOids.Contains(digestOid))
+					throw new InvalidOperationException("Cannot register new digest OIDs after the data stream is opened");
+       		}
+       		else
+       		{
+				_messageDigestOids.Add(digestOid);
+       		}
+		}
+
+		private void ConfigureDigest(
+			string digestOid)
+		{
+       		RegisterDigestOid(digestOid);
+
+       		string digestName = Helper.GetDigestAlgName(digestOid);
+			IDigest dig = (IDigest)_messageDigests[digestName];
+			if (dig == null)
+			{
+				if (_messageDigestsLocked)
+					throw new InvalidOperationException("Cannot configure new digests after the data stream is opened");
+
+            	dig = Helper.GetDigestInstance(digestName);
+            	_messageDigests[digestName] = dig;
+            }
+		}
+
+		// TODO Make public?
+		internal void Generate(
+			Stream			outStream,
+			string			eContentType,
+			bool			encapsulate,
+			Stream			dataOutputStream,
+			CmsProcessable	content)
+		{
+			Stream signedOut = Open(outStream, eContentType, encapsulate, dataOutputStream);
+			if (content != null)
+			{
+				content.Write(signedOut);
+			}
+            signedOut.Dispose();
+		}
+
+		// 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)
+		{
+			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(_signers))
+            {
+                return new DerInteger(3);
+            }
+
+            return new DerInteger(1);
+        }
+
+		private bool CheckForVersion3(
+			IList signerInfos)
+		{
+			foreach (SignerInformation si in signerInfos)
+			{
+				SignerInfo s = SignerInfo.GetInstance(si.ToSignerInfo());
+
+				if (s.Version.Value.IntValue == 3)
+				{
+					return true;
+				}
+			}
+
+			return false;
+		}
+
+		private static Stream AttachDigestsToOutputStream(ICollection digests, Stream s)
+		{
+			Stream result = s;
+			foreach (IDigest digest in digests)
+			{
+				result = GetSafeTeeOutputStream(result, new DigOutputStream(digest));
+			}
+			return result;
+		}
+
+		private static Stream GetSafeOutputStream(Stream s)
+		{
+			if (s == null)
+				return new NullOutputStream();
+			return s;
+		}
+
+		private static Stream GetSafeTeeOutputStream(Stream s1, Stream s2)
+		{
+			if (s1 == null)
+				return GetSafeOutputStream(s2);
+			if (s2 == null)
+				return GetSafeOutputStream(s1);
+			return new TeeOutputStream(s1, s2);
+		}
+
+		private class CmsSignedDataOutputStream
+            : BaseOutputStream
+        {
+			private readonly CmsSignedDataStreamGenerator outer;
+
+			private Stream					_out;
+            private DerObjectIdentifier		_contentOID;
+            private BerSequenceGenerator	_sGen;
+            private BerSequenceGenerator	_sigGen;
+            private BerSequenceGenerator	_eiGen;
+
+			public CmsSignedDataOutputStream(
+				CmsSignedDataStreamGenerator	outer,
+				Stream							outStream,
+                string							contentOID,
+                BerSequenceGenerator			sGen,
+                BerSequenceGenerator			sigGen,
+                BerSequenceGenerator			eiGen)
+            {
+				this.outer = outer;
+
+				_out = outStream;
+                _contentOID = new DerObjectIdentifier(contentOID);
+                _sGen = sGen;
+                _sigGen = sigGen;
+                _eiGen = eiGen;
+            }
+
+			public override void WriteByte(
+                byte b)
+            {
+                _out.WriteByte(b);
+            }
+
+			public override void Write(
+                byte[]	bytes,
+                int		off,
+                int		len)
+            {
+                _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();
+
+                    outer._digests.Clear();    // clear the current preserved digest state
+
+                    if (outer._certs.Count > 0)
+                    {
+                        Asn1Set certs = CmsUtilities.CreateBerSetFromList(outer._certs);
+
+                        WriteToGenerator(_sigGen, new BerTaggedObject(false, 0, certs));
+                    }
+
+                    if (outer._crls.Count > 0)
+                    {
+                        Asn1Set crls = CmsUtilities.CreateBerSetFromList(outer._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));
+                    }
+
+                    // 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();
+
+                    //
+                    // 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();
+
+                            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());
+                        }
+                    }
+
+                    WriteToGenerator(_sigGen, new DerSet(signerInfos));
+
+                    _sigGen.Close();
+                    _sGen.Close();
+                }
+
+				base.Dispose(disposing);
+			}
+
+			private static void WriteToGenerator(
+				Asn1Generator	ag,
+				Asn1Encodable	ae)
+			{
+				byte[] encoded = ae.GetEncoded();
+				ag.GetRawOutputStream().Write(encoded, 0, encoded.Length);
+			}
+		}
+    }
+}
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
new file mode 100644
index 000000000..1626fb8b4
--- /dev/null
+++ b/Crypto/src/cms/CMSStreamException.cs
@@ -0,0 +1,26 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+    public class CmsStreamException
+        : IOException
+    {
+		public CmsStreamException()
+		{
+		}
+
+		public CmsStreamException(
+			string name)
+			: base(name)
+        {
+        }
+
+		public CmsStreamException(
+			string		name,
+			Exception	e)
+			: base(name, e)
+        {
+        }
+    }
+}
diff --git a/Crypto/src/cms/CMSTypedStream.cs b/Crypto/src/cms/CMSTypedStream.cs
new file mode 100644
index 000000000..576edf234
--- /dev/null
+++ b/Crypto/src/cms/CMSTypedStream.cs
@@ -0,0 +1,72 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	public class CmsTypedStream
+	{
+		private const int BufferSize = 32 * 1024;
+
+		private readonly string	_oid;
+		private readonly Stream	_in;
+
+		public CmsTypedStream(
+			Stream inStream)
+			: this(PkcsObjectIdentifiers.Data.Id, inStream, BufferSize)
+		{
+		}
+
+		public CmsTypedStream(
+			string oid,
+			Stream inStream)
+			: this(oid, inStream, BufferSize)
+		{
+		}
+
+		public CmsTypedStream(
+			string	oid,
+			Stream	inStream,
+			int		bufSize)
+		{
+			_oid = oid;
+#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE
+			_in = new FullReaderStream(inStream);
+#else
+			_in = new FullReaderStream(new BufferedStream(inStream, bufSize));
+#endif
+		}
+
+		public string ContentType
+		{
+			get { return _oid; }
+		}
+
+		public Stream ContentStream
+		{
+			get { return _in; }
+		}
+
+		public void Drain()
+		{
+			Streams.Drain(_in);
+            _in.Dispose();
+		}
+
+		private class FullReaderStream : FilterStream
+		{
+			internal FullReaderStream(Stream input)
+				: base(input)
+			{
+			}
+
+			public override int Read(byte[]	buf, int off, int len)
+			{
+				return Streams.ReadFully(base.s, buf, off, len);
+			}
+		}
+	}
+}
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
new file mode 100644
index 000000000..0e93392d9
--- /dev/null
+++ b/Crypto/src/cms/DefaultSignedAttributeTableGenerator.cs
@@ -0,0 +1,124 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+	/**
+	 * Default signed attributes generator.
+	 */
+	public class DefaultSignedAttributeTableGenerator
+		: CmsAttributeTableGenerator
+	{
+		private readonly IDictionary table;
+
+		/**
+		 * Initialise to use all defaults
+		 */
+		public DefaultSignedAttributeTableGenerator()
+		{
+			table = Platform.CreateHashtable();
+		}
+
+		/**
+		 * Initialise with some extra attributes or overrides.
+		 *
+		 * @param attributeTable initial attribute table to use.
+		 */
+		public DefaultSignedAttributeTableGenerator(
+			AttributeTable attributeTable)
+		{
+			if (attributeTable != null)
+			{
+				table = attributeTable.ToDictionary();
+			}
+			else
+			{
+				table = Platform.CreateHashtable();
+			}
+		}
+
+#if (SILVERLIGHT || PORTABLE)
+        /**
+		 * 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
+		 * messageDigest will override the generated ones.
+		 *
+		 * @param parameters source parameters for table generation.
+		 *
+		 * @return a filled in Hashtable of attributes.
+		 */
+		protected virtual IDictionary createStandardAttributeTable(
+			IDictionary parameters)
+		{
+            IDictionary std = Platform.CreateHashtable(table);
+            DoCreateStandardAttributeTable(parameters, std);
+            return std;
+		}
+#else
+        /**
+		 * 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
+		 * messageDigest will override the generated ones.
+		 *
+		 * @param parameters source parameters for table generation.
+		 *
+		 * @return a filled in Hashtable of attributes.
+		 */
+		protected virtual Hashtable createStandardAttributeTable(
+			IDictionary parameters)
+		{
+            Hashtable std = new Hashtable(table);
+            DoCreateStandardAttributeTable(parameters, std);
+			return std;
+		}
+#endif
+
+        private void DoCreateStandardAttributeTable(IDictionary parameters, IDictionary std)
+        {
+            // contentType will be absent if we're trying to generate a counter signature.
+            if (parameters.Contains(CmsAttributeTableParameter.ContentType))
+            {
+                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.SigningTime))
+            {
+                Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.SigningTime,
+                    new DerSet(new Time(DateTime.UtcNow)));
+                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;
+            }
+        }
+
+        /**
+		 * @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/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
new file mode 100644
index 000000000..38a94b0a4
--- /dev/null
+++ b/Crypto/src/cms/KeyAgreeRecipientInformation.cs
@@ -0,0 +1,226 @@
+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.Pkcs;
+using Org.BouncyCastle.Asn1.Utilities;
+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.Pkcs;
+using Org.BouncyCastle.Security;
+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);
+		}
+	}
+}
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/NullOutputStream.cs b/Crypto/src/cms/NullOutputStream.cs
new file mode 100644
index 000000000..ed937bdeb
--- /dev/null
+++ b/Crypto/src/cms/NullOutputStream.cs
@@ -0,0 +1,20 @@
+using System;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Cms
+{
+	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/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/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
new file mode 100644
index 000000000..87413b69d
--- /dev/null
+++ b/Crypto/src/crypto/BufferedAeadBlockCipher.cs
@@ -0,0 +1,259 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto
+{
+	/**
+	* The AEAD block ciphers already handle buffering internally, so this class
+	* just takes care of implementing IBufferedCipher methods.
+	*/
+	public class BufferedAeadBlockCipher
+		: BufferedCipherBase
+	{
+		private readonly IAeadBlockCipher cipher;
+
+		public BufferedAeadBlockCipher(
+			IAeadBlockCipher cipher)
+		{
+			if (cipher == null)
+				throw new ArgumentNullException("cipher");
+
+			this.cipher = cipher;
+		}
+
+		public override string AlgorithmName
+		{
+			get { return cipher.AlgorithmName; }
+		}
+
+		/**
+		* 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)
+		{
+			if (parameters is ParametersWithRandom)
+			{
+				parameters = ((ParametersWithRandom) parameters).Parameters;
+			}
+
+			cipher.Init(forEncryption, parameters);
+		}
+
+		/**
+		* return the blocksize for the underlying cipher.
+		*
+		* @return the blocksize for the underlying cipher.
+		*/
+		public override int GetBlockSize()
+		{
+			return cipher.GetBlockSize();
+		}
+
+		/**
+		* return the size of the output buffer required for an update
+		* an input of len bytes.
+		*
+		* @param len the length of the input.
+		* @return the space required to accommodate a call to update
+		* with len bytes of input.
+		*/
+		public override int GetUpdateOutputSize(
+			int length)
+		{
+			return cipher.GetUpdateOutputSize(length);
+		}
+
+		/**
+		* return the size of the output buffer required for an update plus a
+		* doFinal with an input of len bytes.
+		*
+		* @param len the length of the input.
+		* @return the space required to accommodate a call to update and doFinal
+		* with len bytes of input.
+		*/
+		public override int GetOutputSize(
+			int length)
+		{
+			return cipher.GetOutputSize(length);
+		}
+
+		/**
+		* 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)
+		{
+			return cipher.ProcessByte(input, output, outOff);
+		}
+
+		public override byte[] ProcessByte(
+			byte input)
+		{
+			int outLength = GetUpdateOutputSize(1);
+
+			byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
+
+			int pos = ProcessByte(input, outBytes, 0);
+
+			if (outLength > 0 && pos < outLength)
+			{
+				byte[] tmp = new byte[pos];
+				Array.Copy(outBytes, 0, tmp, 0, pos);
+				outBytes = tmp;
+			}
+
+			return outBytes;
+		}
+
+		public override byte[] ProcessBytes(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			if (input == null)
+				throw new ArgumentNullException("input");
+			if (length < 1)
+				return null;
+
+			int outLength = GetUpdateOutputSize(length);
+
+			byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
+
+			int pos = ProcessBytes(input, inOff, length, outBytes, 0);
+
+			if (outLength > 0 && pos < outLength)
+			{
+				byte[] tmp = new byte[pos];
+				Array.Copy(outBytes, 0, tmp, 0, pos);
+				outBytes = tmp;
+			}
+
+			return outBytes;
+		}
+
+		/**
+		* 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)
+		{
+			return cipher.ProcessBytes(input, inOff, length, output, outOff);
+		}
+
+		public override byte[] DoFinal()
+		{
+			byte[] outBytes = EmptyBuffer;
+
+			int length = GetOutputSize(0);
+			if (length > 0)
+			{
+				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;
+				}
+			}
+
+			return outBytes;
+		}
+
+		public override byte[] DoFinal(
+			byte[]	input,
+			int		inOff,
+			int		inLen)
+		{
+			if (input == null)
+				throw new ArgumentNullException("input");
+
+			int length = GetOutputSize(inLen);
+
+			byte[] outBytes = EmptyBuffer;
+
+			if (length > 0)
+			{
+				outBytes = new byte[length];
+
+				int pos = (inLen > 0)
+					?	ProcessBytes(input, inOff, inLen, outBytes, 0)
+					:	0;
+
+				pos += DoFinal(outBytes, pos);
+
+				if (pos < outBytes.Length)
+				{
+					byte[] tmp = new byte[pos];
+					Array.Copy(outBytes, 0, tmp, 0, pos);
+					outBytes = tmp;
+				}
+			}
+
+			return outBytes;
+		}
+
+		/**
+		* Process the last block in the buffer.
+		*
+		* @param out the array the block currently being held is copied into.
+		* @param outOff the offset at which the copying starts.
+		* @return the number of output bytes copied to out.
+		* @exception DataLengthException if there is insufficient space in out for
+		* the output, or the input is not block size aligned and should be.
+		* @exception InvalidOperationException if the underlying cipher is not
+		* initialised.
+		* @exception InvalidCipherTextException if padding is expected and not found.
+		* @exception DataLengthException if the input is not block size
+		* aligned.
+		*/
+		public override int DoFinal(
+			byte[]	output,
+			int		outOff)
+		{
+			return cipher.DoFinal(output, outOff);
+		}
+
+		/**
+		* Reset the buffer and cipher. After resetting the object is in the same
+		* state as it was after the last init (if there was one).
+		*/
+		public override void Reset()
+		{
+			cipher.Reset();
+		}
+	}
+}
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
new file mode 100644
index 000000000..72bdfed67
--- /dev/null
+++ b/Crypto/src/crypto/BufferedBlockCipher.cs
@@ -0,0 +1,378 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto
+{
+	/**
+	* A wrapper class that allows block ciphers to be used to process data in
+	* a piecemeal fashion. The BufferedBlockCipher outputs a block only when the
+	* buffer is full and more data is being added, or on a doFinal.
+	* <p>
+	* Note: in the case where the underlying cipher is either a CFB cipher or an
+	* OFB one the last block may not be a multiple of the block size.
+	* </p>
+	*/
+	public class BufferedBlockCipher
+		: BufferedCipherBase
+	{
+		internal byte[]			buf;
+		internal int			bufOff;
+		internal bool			forEncryption;
+		internal IBlockCipher	cipher;
+
+		/**
+		* constructor for subclasses
+		*/
+		protected BufferedBlockCipher()
+		{
+		}
+
+		/**
+		* Create a buffered block cipher without padding.
+		*
+		* @param cipher the underlying block cipher this buffering object wraps.
+		* false otherwise.
+		*/
+		public BufferedBlockCipher(
+			IBlockCipher cipher)
+		{
+			if (cipher == null)
+				throw new ArgumentNullException("cipher");
+
+			this.cipher = cipher;
+			buf = new byte[cipher.GetBlockSize()];
+			bufOff = 0;
+		}
+
+		public override string AlgorithmName
+		{
+			get { return cipher.AlgorithmName; }
+		}
+
+		/**
+		* 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.
+		*/
+		// Note: This doubles as the Init in the event that this cipher is being used as an IWrapper
+		public override void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			this.forEncryption = forEncryption;
+
+			if (parameters is ParametersWithRandom)
+			{
+				parameters = ((ParametersWithRandom) parameters).Parameters;
+			}
+
+			Reset();
+
+			cipher.Init(forEncryption, parameters);
+		}
+
+		/**
+		* return the blocksize for the underlying cipher.
+		*
+		* @return the blocksize for the underlying cipher.
+		*/
+		public override int GetBlockSize()
+		{
+			return cipher.GetBlockSize();
+		}
+
+		/**
+		* return the size of the output buffer required for an update
+		* an input of len bytes.
+		*
+		* @param len the length of the input.
+		* @return the space required to accommodate a call to update
+		* with len bytes of input.
+		*/
+		public override int GetUpdateOutputSize(
+			int length)
+		{
+			int total = length + bufOff;
+			int leftOver = total % buf.Length;
+			return total - leftOver;
+		}
+
+		/**
+		* return the size of the output buffer required for an update plus a
+		* doFinal with an input of 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)
+		{
+			// Note: Can assume IsPartialBlockOkay is true for purposes of this calculation
+			return length + bufOff;
+		}
+
+		/**
+		* process a single byte, producing an output block if neccessary.
+		*
+		* @param in the input byte.
+		* @param out the space for any output that might be produced.
+		* @param outOff the offset from which the output will be copied.
+		* @return the number of output bytes copied to out.
+		* @exception DataLengthException if there isn't enough space in out.
+		* @exception InvalidOperationException if the cipher isn't initialised.
+		*/
+		public override int ProcessByte(
+			byte	input,
+			byte[]	output,
+			int		outOff)
+		{
+			buf[bufOff++] = input;
+
+			if (bufOff == buf.Length)
+			{
+				if ((outOff + buf.Length) > output.Length)
+					throw new DataLengthException("output buffer too short");
+
+				bufOff = 0;
+				return cipher.ProcessBlock(buf, 0, output, outOff);
+			}
+
+			return 0;
+		}
+
+		public override byte[] ProcessByte(
+			byte input)
+		{
+			int outLength = GetUpdateOutputSize(1);
+
+			byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
+
+			int pos = ProcessByte(input, outBytes, 0);
+
+			if (outLength > 0 && pos < outLength)
+			{
+				byte[] tmp = new byte[pos];
+				Array.Copy(outBytes, 0, tmp, 0, pos);
+				outBytes = tmp;
+			}
+
+			return outBytes;
+		}
+
+		public override byte[] ProcessBytes(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			if (input == null)
+				throw new ArgumentNullException("input");
+			if (length < 1)
+				return null;
+
+			int outLength = GetUpdateOutputSize(length);
+
+			byte[] outBytes = outLength > 0 ? new byte[outLength] : null;
+
+			int pos = ProcessBytes(input, inOff, length, outBytes, 0);
+
+			if (outLength > 0 && pos < outLength)
+			{
+				byte[] tmp = new byte[pos];
+				Array.Copy(outBytes, 0, tmp, 0, pos);
+				outBytes = tmp;
+			}
+
+			return outBytes;
+		}
+
+		/**
+		* 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 < 1)
+			{
+				if (length < 0)
+					throw new ArgumentException("Can't have a negative input length!");
+
+				return 0;
+			}
+
+			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;
+			if (bufOff == buf.Length)
+			{
+				resultLen += cipher.ProcessBlock(buf, 0, output, outOff + resultLen);
+				bufOff = 0;
+			}
+			return resultLen;
+		}
+
+		public override byte[] DoFinal()
+		{
+			byte[] outBytes = EmptyBuffer;
+
+			int length = GetOutputSize(0);
+			if (length > 0)
+			{
+				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;
+				}
+			}
+			else
+			{
+				Reset();
+			}
+
+			return outBytes;
+		}
+
+		public override byte[] DoFinal(
+			byte[]	input,
+			int		inOff,
+			int		inLen)
+		{
+			if (input == null)
+				throw new ArgumentNullException("input");
+
+			int length = GetOutputSize(inLen);
+
+			byte[] outBytes = EmptyBuffer;
+
+			if (length > 0)
+			{
+				outBytes = new byte[length];
+
+				int pos = (inLen > 0)
+					?	ProcessBytes(input, inOff, inLen, outBytes, 0)
+					:	0;
+
+				pos += DoFinal(outBytes, pos);
+
+				if (pos < outBytes.Length)
+				{
+					byte[] tmp = new byte[pos];
+					Array.Copy(outBytes, 0, tmp, 0, pos);
+					outBytes = tmp;
+				}
+			}
+			else
+			{
+				Reset();
+			}
+
+			return outBytes;
+		}
+
+		/**
+		* Process the last block in the buffer.
+		*
+		* @param out the array the block currently being held is copied into.
+		* @param outOff the offset at which the copying starts.
+		* @return the number of output bytes copied to out.
+		* @exception DataLengthException if there is insufficient space in out for
+		* the output, or the input is not block size aligned and should be.
+		* @exception InvalidOperationException if the underlying cipher is not
+		* initialised.
+		* @exception InvalidCipherTextException if padding is expected and not found.
+		* @exception DataLengthException if the input is not block size
+		* aligned.
+		*/
+		public override int DoFinal(
+			byte[]	output,
+			int		outOff)
+		{
+			try
+			{
+				if (bufOff != 0)
+				{
+					if (!cipher.IsPartialBlockOkay)
+					{
+						throw new DataLengthException("data not block size aligned");
+					}
+	
+					if (outOff + bufOff > output.Length)
+					{
+						throw new DataLengthException("output buffer too short for DoFinal()");
+					}
+	
+					// NB: Can't copy directly, or we may write too much output
+					cipher.ProcessBlock(buf, 0, buf, 0);
+					Array.Copy(buf, 0, output, outOff, bufOff);
+				}
+
+				return bufOff;
+			}
+			finally
+			{
+				Reset();
+			}
+		}
+
+		/**
+		* Reset the buffer and cipher. After resetting the object is in the same
+		* state as it was after the last init (if there was one).
+		*/
+		public override void Reset()
+		{
+			Array.Clear(buf, 0, buf.Length);
+			bufOff = 0;
+
+			cipher.Reset();
+		}
+	}
+}
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
new file mode 100644
index 000000000..c012063bb
--- /dev/null
+++ b/Crypto/src/crypto/CryptoException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    public class CryptoException
+		: Exception
+    {
+        public CryptoException()
+        {
+        }
+
+		public CryptoException(
+            string message)
+			: base(message)
+        {
+        }
+
+		public CryptoException(
+            string		message,
+            Exception	exception)
+			: base(message, exception)
+        {
+        }
+    }
+}
diff --git a/Crypto/src/crypto/DataLengthException.cs b/Crypto/src/crypto/DataLengthException.cs
new file mode 100644
index 000000000..8bd695bbc
--- /dev/null
+++ b/Crypto/src/crypto/DataLengthException.cs
@@ -0,0 +1,39 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * this exception is thrown if a buffer that is meant to have output
+     * copied into it turns out to be too short, or if we've been given
+     * insufficient input. In general this exception will Get thrown rather
+     * than an ArrayOutOfBounds exception.
+     */
+    public class DataLengthException
+		: CryptoException
+	{
+        /**
+        * base constructor.
+		*/
+        public DataLengthException()
+        {
+        }
+
+		/**
+         * create a DataLengthException with the given message.
+         *
+         * @param message the message to be carried with the exception.
+         */
+        public DataLengthException(
+            string message)
+			: base(message)
+        {
+		}
+
+		public DataLengthException(
+            string		message,
+            Exception	exception)
+			: base(message, exception)
+        {
+        }
+	}
+}
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
new file mode 100644
index 000000000..8bd363d4e
--- /dev/null
+++ b/Crypto/src/crypto/IBasicAgreement.cs
@@ -0,0 +1,24 @@
+using System;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * The basic interface that basic Diffie-Hellman implementations
+     * conforms to.
+     */
+    public interface IBasicAgreement
+    {
+        /**
+         * initialise the agreement engine.
+         */
+        void Init(ICipherParameters parameters);
+
+        /**
+         * given a public key from a given party calculate the next
+         * message in the agreement sequence.
+         */
+        BigInteger CalculateAgreement(ICipherParameters pubKey);
+    }
+
+}
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
new file mode 100644
index 000000000..598ea278d
--- /dev/null
+++ b/Crypto/src/crypto/InvalidCipherTextException.cs
@@ -0,0 +1,37 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /**
+     * this exception is thrown whenever we find something we don't expect in a
+     * message.
+     */
+    public class InvalidCipherTextException
+		: CryptoException
+    {
+		/**
+		* base constructor.
+		*/
+        public InvalidCipherTextException()
+        {
+        }
+
+		/**
+         * create a InvalidCipherTextException with the given message.
+         *
+         * @param message the message to be carried with the exception.
+         */
+        public InvalidCipherTextException(
+            string message)
+			: base(message)
+        {
+        }
+
+		public InvalidCipherTextException(
+            string		message,
+            Exception	exception)
+			: base(message, exception)
+        {
+        }
+    }
+}
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
new file mode 100644
index 000000000..9fa28abb0
--- /dev/null
+++ b/Crypto/src/crypto/MaxBytesExceededException.cs
@@ -0,0 +1,29 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+	/// <summary>
+	/// 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
+		: CryptoException
+	{
+		public MaxBytesExceededException()
+		{
+		}
+
+		public MaxBytesExceededException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public MaxBytesExceededException(
+			string		message,
+			Exception	e)
+			: base(message, e)
+		{
+		}
+	}
+}
diff --git a/Crypto/src/crypto/PbeParametersGenerator.cs b/Crypto/src/crypto/PbeParametersGenerator.cs
new file mode 100644
index 000000000..0e96abd0f
--- /dev/null
+++ b/Crypto/src/crypto/PbeParametersGenerator.cs
@@ -0,0 +1,190 @@
+using System;
+using System.Text;
+
+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)
+		{
+            return Strings.ToAsciiByteArray(password);
+		}
+
+		[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;
+		}
+	}
+}
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
new file mode 100644
index 000000000..5a5277049
--- /dev/null
+++ b/Crypto/src/crypto/agreement/DHBasicAgreement.cs
@@ -0,0 +1,60 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+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);
+		}
+	}
+
+}
diff --git a/Crypto/src/crypto/agreement/ECDHBasicAgreement.cs b/Crypto/src/crypto/agreement/ECDHBasicAgreement.cs
new file mode 100644
index 000000000..f272e4969
--- /dev/null
+++ b/Crypto/src/crypto/agreement/ECDHBasicAgreement.cs
@@ -0,0 +1,50 @@
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+    /**
+     * P1363 7.2.1 ECSVDP-DH
+     *
+     * ECSVDP-DH is Elliptic Curve Secret Value Derivation Primitive,
+     * Diffie-Hellman version. It is based on the work of [DH76], [Mil86],
+     * and [Kob87]. This primitive derives a shared secret value from one
+     * party's private key and another party's public key, where both have
+     * the same set of EC domain parameters. If two parties correctly
+     * execute this primitive, they will produce the same output. This
+     * primitive can be invoked by a scheme to derive a shared secret key;
+     * specifically, it may be used with the schemes ECKAS-DH1 and
+     * DL/ECKAS-DH2. It assumes that the input keys are valid (see also
+     * Section 7.2.2).
+     */
+    public class ECDHBasicAgreement
+		: IBasicAgreement
+    {
+        protected internal ECPrivateKeyParameters privKey;
+
+        public void Init(
+			ICipherParameters parameters)
+        {
+			if (parameters is ParametersWithRandom)
+			{
+				parameters = ((ParametersWithRandom)parameters).Parameters;
+			}
+
+			this.privKey = (ECPrivateKeyParameters)parameters;
+        }
+
+        public virtual BigInteger CalculateAgreement(
+            ICipherParameters pubKey)
+        {
+            ECPublicKeyParameters pub = (ECPublicKeyParameters) pubKey;
+            ECPoint P = pub.Q.Multiply(privKey.D);
+
+            // if ( p.IsInfinity ) throw new Exception("d*Q == infinity");
+
+            return P.X.ToBigInteger();
+        }
+    }
+
+}
diff --git a/Crypto/src/crypto/agreement/ECDHCBasicAgreement.cs b/Crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
new file mode 100644
index 000000000..905d241fc
--- /dev/null
+++ b/Crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
@@ -0,0 +1,58 @@
+using System;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+    /**
+     * P1363 7.2.2 ECSVDP-DHC
+     *
+     * ECSVDP-DHC is Elliptic Curve Secret Value Derivation Primitive,
+     * Diffie-Hellman version with cofactor multiplication. It is based on
+     * the work of [DH76], [Mil86], [Kob87], [LMQ98] and [Kal98a]. This
+     * primitive derives a shared secret value from one party's private key
+     * and another party's public key, where both have the same set of EC
+     * domain parameters. If two parties correctly execute this primitive,
+     * they will produce the same output. This primitive can be invoked by a
+     * scheme to derive a shared secret key; specifically, it may be used
+     * with the schemes ECKAS-DH1 and DL/ECKAS-DH2. It does not assume the
+     * validity of the input public key (see also Section 7.2.1).
+     * <p>
+     * Note: As stated P1363 compatibility mode with ECDH can be preset, and
+     * in this case the implementation doesn't have a ECDH compatibility mode
+     * (if you want that just use ECDHBasicAgreement and note they both implement
+     * BasicAgreement!).</p>
+     */
+    public class ECDHCBasicAgreement
+		: IBasicAgreement
+    {
+        private ECPrivateKeyParameters key;
+
+        public void Init(
+            ICipherParameters parameters)
+        {
+			if (parameters is ParametersWithRandom)
+			{
+				parameters = ((ParametersWithRandom) parameters).Parameters;
+			}
+
+			this.key = (ECPrivateKeyParameters)parameters;
+        }
+
+        public 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");
+
+            return P.X.ToBigInteger();
+        }
+    }
+
+}
diff --git a/Crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs b/Crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs
new file mode 100644
index 000000000..28437a268
--- /dev/null
+++ b/Crypto/src/crypto/agreement/ECDHWithKdfBasicAgreement.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.Agreement.Kdf;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+	public class ECDHWithKdfBasicAgreement
+		: ECDHBasicAgreement
+	{
+		private readonly string algorithm;
+		private readonly IDerivationFunction kdf;
+
+		public ECDHWithKdfBasicAgreement(
+			string				algorithm,
+			IDerivationFunction	kdf)
+		{
+			if (algorithm == null)
+				throw new ArgumentNullException("algorithm");
+			if (kdf == null)
+				throw new ArgumentNullException("kdf");
+
+			this.algorithm = algorithm;
+			this.kdf = kdf;
+		}
+
+		public override BigInteger CalculateAgreement(
+			ICipherParameters pubKey)
+		{
+			// Note that the ec.KeyAgreement class in JCE only uses kdf in one
+			// of the engineGenerateSecret methods.
+
+			BigInteger result = base.CalculateAgreement(pubKey);
+
+			int keySize = GeneratorUtilities.GetDefaultKeySize(algorithm);
+
+			DHKdfParameters dhKdfParams = new DHKdfParameters(
+				new DerObjectIdentifier(algorithm),
+				keySize,
+				bigIntToBytes(result));
+
+			kdf.Init(dhKdfParams);
+
+			byte[] keyBytes = new byte[keySize / 8];
+			kdf.GenerateBytes(keyBytes, 0, keyBytes.Length);
+
+			return new BigInteger(1, keyBytes);
+		}
+
+		private byte[] bigIntToBytes(
+			BigInteger r)
+		{
+			int byteLength = X9IntegerConverter.GetByteLength(privKey.Parameters.G.X);
+			return X9IntegerConverter.IntegerToBytes(r, byteLength);
+		}
+	}
+}
diff --git a/Crypto/src/crypto/agreement/ECMqvBasicAgreement.cs b/Crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
new file mode 100644
index 000000000..51faa8e49
--- /dev/null
+++ b/Crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
@@ -0,0 +1,85 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs b/Crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs
new file mode 100644
index 000000000..093ce4056
--- /dev/null
+++ b/Crypto/src/crypto/agreement/ECMqvWithKdfBasicAgreement.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.Agreement.Kdf;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Agreement
+{
+	public class ECMqvWithKdfBasicAgreement
+		: ECMqvBasicAgreement
+	{
+		private readonly string algorithm;
+		private readonly IDerivationFunction kdf;
+
+		public ECMqvWithKdfBasicAgreement(
+			string				algorithm,
+			IDerivationFunction	kdf)
+		{
+			if (algorithm == null)
+				throw new ArgumentNullException("algorithm");
+			if (kdf == null)
+				throw new ArgumentNullException("kdf");
+
+			this.algorithm = algorithm;
+			this.kdf = kdf;
+		}
+
+		public override BigInteger CalculateAgreement(
+			ICipherParameters pubKey)
+		{
+			// Note that the ec.KeyAgreement class in JCE only uses kdf in one
+			// of the engineGenerateSecret methods.
+
+			BigInteger result = base.CalculateAgreement(pubKey);
+
+			int keySize = GeneratorUtilities.GetDefaultKeySize(algorithm);
+
+			DHKdfParameters dhKdfParams = new DHKdfParameters(
+				new DerObjectIdentifier(algorithm),
+				keySize,
+				bigIntToBytes(result));
+
+			kdf.Init(dhKdfParams);
+
+			byte[] keyBytes = new byte[keySize / 8];
+			kdf.GenerateBytes(keyBytes, 0, keyBytes.Length);
+
+			return new BigInteger(1, keyBytes);
+		}
+
+		private byte[] bigIntToBytes(
+			BigInteger r)
+		{
+			int byteLength = X9IntegerConverter.GetByteLength(privParams.StaticPrivateKey.Parameters.G.X);
+			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
new file mode 100644
index 000000000..fa2921539
--- /dev/null
+++ b/Crypto/src/crypto/agreement/kdf/DHKekGenerator.cs
@@ -0,0 +1,129 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+
+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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs b/Crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs
new file mode 100644
index 000000000..7d55aa485
--- /dev/null
+++ b/Crypto/src/crypto/agreement/kdf/ECDHKekGenerator.cs
@@ -0,0 +1,71 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Parameters;
+
+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;
+		}
+	}
+}
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
new file mode 100644
index 000000000..9f0bec9e6
--- /dev/null
+++ b/Crypto/src/crypto/digests/GOST3411Digest.cs
@@ -0,0 +1,343 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+	/**
+	* implementation of GOST R 34.11-94
+	*/
+	public class Gost3411Digest
+		: IDigest
+	{
+		private const int DIGEST_LENGTH = 32;
+
+		private byte[]	H = new byte[32], L = new byte[32],
+						M = new byte[32], Sum = new byte[32];
+		private byte[][] C = MakeC();
+
+		private byte[]	xBuf = new byte[32];
+		private int		xBufOff;
+		private ulong	byteCount;
+
+		private readonly IBlockCipher cipher = new Gost28147Engine();
+		private readonly byte[] sBox;
+
+		private static byte[][] MakeC()
+		{
+			byte[][] c = new byte[4][];
+			for (int i = 0; i < 4; ++i)
+			{
+				c[i] = new byte[32];
+			}
+			return c;
+		}
+
+		/**
+		 * Standard constructor
+		 */
+		public Gost3411Digest()
+		{
+			sBox = Gost28147Engine.GetSBox("D-A");
+			cipher.Init(true, new ParametersWithSBox(null, sBox));
+
+			Reset();
+		}
+
+		/**
+		 * Constructor to allow use of a particular sbox with GOST28147
+		 * @see GOST28147Engine#getSBox(String)
+		 */
+		public Gost3411Digest(byte[] sBoxParam)
+		{
+			sBox = Arrays.Clone(sBoxParam);
+			cipher.Init(true, new ParametersWithSBox(null, sBox));
+
+			Reset();
+		}
+
+		/**
+		 * Copy constructor.  This will copy the state of the provided
+		 * message digest.
+		 */
+		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;
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Gost3411"; }
+		}
+
+		public int GetDigestSize()
+		{
+			return DIGEST_LENGTH;
+		}
+
+		public void Update(
+			byte input)
+		{
+			xBuf[xBufOff++] = input;
+			if (xBufOff == xBuf.Length)
+			{
+				sumByteArray(xBuf); // calc sum M
+				processBlock(xBuf, 0);
+				xBufOff = 0;
+			}
+			byteCount++;
+		}
+
+		public void BlockUpdate(
+			byte[]	input,
+			int		inOff,
+			int		length)
+		{
+			while ((xBufOff != 0) && (length > 0))
+			{
+				Update(input[inOff]);
+				inOff++;
+				length--;
+			}
+
+			while (length > xBuf.Length)
+			{
+				Array.Copy(input, inOff, xBuf, 0, xBuf.Length);
+
+				sumByteArray(xBuf); // calc sum M
+				processBlock(xBuf, 0);
+				inOff += xBuf.Length;
+				length -= xBuf.Length;
+				byteCount += (uint)xBuf.Length;
+			}
+
+			// load in the remainder.
+			while (length > 0)
+			{
+				Update(input[inOff]);
+				inOff++;
+				length--;
+			}
+		}
+
+		// (i + 1 + 4(k - 1)) = 8i + k      i = 0-3, k = 1-8
+		private byte[] K = new byte[32];
+
+		private byte[] P(byte[] input)
+		{
+			int fourK = 0;
+			for(int k = 0; k < 8; k++)
+			{
+				K[fourK++] = input[k];
+				K[fourK++] = input[8 + k];
+				K[fourK++] = input[16 + k];
+				K[fourK++] = input[24 + k];
+			}
+
+			return K;
+		}
+
+		//A (x) = (x0 ^ x1) || x3 || x2 || x1
+		byte[] a = new byte[8];
+		private byte[] A(byte[] input)
+		{
+			for(int j=0; j<8; j++)
+			{
+				a[j]=(byte)(input[j] ^ input[j+8]);
+			}
+
+			Array.Copy(input, 8, input, 0, 24);
+			Array.Copy(a, 0, input, 24, 8);
+
+			return input;
+		}
+
+		//Encrypt function, ECB mode
+		private void E(byte[] key, byte[] s, int sOff, byte[] input, int inOff)
+		{
+			cipher.Init(true, new KeyParameter(key));
+
+			cipher.ProcessBlock(input, inOff, s, sOff);
+		}
+
+		// (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2
+		internal short[] wS = new short[16], w_S = new short[16];
+
+		private void fw(byte[] input)
+		{
+			cpyBytesToShort(input, wS);
+			w_S[15] = (short)(wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]);
+			Array.Copy(wS, 1, w_S, 0, 15);
+			cpyShortToBytes(w_S, input);
+		}
+
+		// block processing
+		internal byte[] S = new byte[32], U = new byte[32], V = new byte[32], W = new byte[32];
+
+		private void processBlock(byte[] input, int inOff)
+		{
+			Array.Copy(input, inOff, M, 0, 32);
+
+			//key step 1
+
+			// H = h3 || h2 || h1 || h0
+			// S = s3 || s2 || s1 || s0
+			H.CopyTo(U, 0);
+			M.CopyTo(V, 0);
+			for (int j=0; j<32; j++)
+			{
+				W[j] = (byte)(U[j]^V[j]);
+			}
+			// Encrypt gost28147-ECB
+			E(P(W), S, 0, H, 0); // s0 = EK0 [h0]
+
+			//keys step 2,3,4
+			for (int i=1; i<4; i++)
+			{
+				byte[] tmpA = A(U);
+				for (int j=0; j<32; j++)
+				{
+					U[j] = (byte)(tmpA[j] ^ C[i][j]);
+				}
+				V = A(A(V));
+				for (int j=0; j<32; j++)
+				{
+					W[j] = (byte)(U[j]^V[j]);
+				}
+				// Encrypt gost28147-ECB
+				E(P(W), S, i * 8, H, i * 8); // si = EKi [hi]
+			}
+
+			// x(M, H) = y61(H^y(M^y12(S)))
+			for(int n = 0; n < 12; n++)
+			{
+				fw(S);
+			}
+			for(int n = 0; n < 32; n++)
+			{
+				S[n] = (byte)(S[n] ^ M[n]);
+			}
+
+			fw(S);
+
+			for(int n = 0; n < 32; n++)
+			{
+				S[n] = (byte)(H[n] ^ S[n]);
+			}
+			for(int n = 0; n < 61; n++)
+			{
+				fw(S);
+			}
+			Array.Copy(S, 0, H, 0, H.Length);
+		}
+
+		private void finish()
+		{
+			ulong bitCount = byteCount * 8;
+			Pack.UInt64_To_LE(bitCount, L);
+
+			while (xBufOff != 0)
+			{
+				Update((byte)0);
+			}
+
+			processBlock(L, 0);
+			processBlock(Sum, 0);
+		}
+
+		public int DoFinal(
+			byte[]  output,
+			int     outOff)
+		{
+			finish();
+
+			H.CopyTo(output, outOff);
+
+			Reset();
+
+			return DIGEST_LENGTH;
+		}
+
+		/**
+		* reset the chaining variables to the IV values.
+		*/
+		private static readonly byte[] C2 = {
+			0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,
+			(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,
+			0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF,0x00,0x00,(byte)0xFF,
+			(byte)0xFF,0x00,0x00,0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF
+		};
+
+		public void Reset()
+		{
+			byteCount = 0;
+			xBufOff = 0;
+
+			Array.Clear(H, 0, H.Length);
+			Array.Clear(L, 0, L.Length);
+			Array.Clear(M, 0, M.Length);
+			Array.Clear(C[1], 0, C[1].Length); // real index C = +1 because index array with 0.
+			Array.Clear(C[3], 0, C[3].Length);
+			Array.Clear(Sum, 0, Sum.Length);
+			Array.Clear(xBuf, 0, xBuf.Length);
+
+			C2.CopyTo(C[2], 0);
+		}
+
+		//  256 bitsblock modul -> (Sum + a mod (2^256))
+		private void sumByteArray(
+			byte[] input)
+		{
+			int carry = 0;
+
+			for (int i = 0; i != Sum.Length; i++)
+			{
+				int sum = (Sum[i] & 0xff) + (input[i] & 0xff) + carry;
+
+				Sum[i] = (byte)sum;
+
+				carry = sum >> 8;
+			}
+		}
+
+		private static void cpyBytesToShort(byte[] S, short[] wS)
+		{
+			for(int i = 0; i < S.Length / 2; i++)
+			{
+				wS[i] = (short)(((S[i*2+1]<<8)&0xFF00)|(S[i*2]&0xFF));
+			}
+		}
+
+		private static void cpyShortToBytes(short[] wS, byte[] S)
+		{
+			for(int i=0; i<S.Length/2; i++)
+			{
+				S[i*2 + 1] = (byte)(wS[i] >> 8);
+				S[i*2] = (byte)wS[i];
+			}
+		}
+
+		public int GetByteLength()
+		{
+			return 32;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/digests/GeneralDigest.cs b/Crypto/src/crypto/digests/GeneralDigest.cs
new file mode 100644
index 000000000..77c17ed58
--- /dev/null
+++ b/Crypto/src/crypto/digests/GeneralDigest.cs
@@ -0,0 +1,118 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /**
+    * base implementation of MD4 family style digest as outlined in
+    * "Handbook of Applied Cryptography", pages 344 - 347.
+    */
+    public abstract class GeneralDigest
+		: IDigest
+    {
+        private const int BYTE_LENGTH = 64;
+
+        private byte[]  xBuf;
+        private int     xBufOff;
+
+        private long    byteCount;
+
+        internal GeneralDigest()
+        {
+            xBuf = new byte[4];
+        }
+
+        internal GeneralDigest(GeneralDigest t)
+        {
+            xBuf = new byte[t.xBuf.Length];
+            Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
+
+            xBufOff = t.xBufOff;
+            byteCount = t.byteCount;
+        }
+
+        public void Update(byte input)
+        {
+            xBuf[xBufOff++] = input;
+
+            if (xBufOff == xBuf.Length)
+            {
+                ProcessWord(xBuf, 0);
+                xBufOff = 0;
+            }
+
+            byteCount++;
+        }
+
+        public void BlockUpdate(
+            byte[]  input,
+            int     inOff,
+            int     length)
+        {
+            //
+            // fill the current word
+            //
+            while ((xBufOff != 0) && (length > 0))
+            {
+                Update(input[inOff]);
+                inOff++;
+                length--;
+            }
+
+            //
+            // process whole words.
+            //
+            while (length > xBuf.Length)
+            {
+                ProcessWord(input, inOff);
+
+                inOff += xBuf.Length;
+                length -= xBuf.Length;
+                byteCount += xBuf.Length;
+            }
+
+            //
+            // load in the remainder.
+            //
+            while (length > 0)
+            {
+                Update(input[inOff]);
+
+                inOff++;
+                length--;
+            }
+        }
+
+        public void Finish()
+        {
+            long    bitLength = (byteCount << 3);
+
+            //
+            // add the pad bytes.
+            //
+            Update((byte)128);
+
+            while (xBufOff != 0) Update((byte)0);
+            ProcessLength(bitLength);
+            ProcessBlock();
+        }
+
+        public virtual void Reset()
+        {
+            byteCount = 0;
+            xBufOff = 0;
+			Array.Clear(xBuf, 0, xBuf.Length);
+        }
+
+		public int GetByteLength()
+		{
+			return BYTE_LENGTH;
+		}
+
+		internal abstract void ProcessWord(byte[] input, int inOff);
+        internal abstract void ProcessLength(long bitLength);
+        internal abstract void ProcessBlock();
+        public abstract string AlgorithmName { get; }
+		public abstract int GetDigestSize();
+        public abstract int DoFinal(byte[] output, int outOff);
+    }
+}
diff --git a/Crypto/src/crypto/digests/LongDigest.cs b/Crypto/src/crypto/digests/LongDigest.cs
new file mode 100644
index 000000000..702753b2b
--- /dev/null
+++ b/Crypto/src/crypto/digests/LongDigest.cs
@@ -0,0 +1,346 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /**
+    * Base class for SHA-384 and SHA-512.
+    */
+    public abstract class LongDigest
+		: IDigest
+    {
+        private int     MyByteLength = 128;
+
+        private byte[]  xBuf;
+        private int     xBufOff;
+
+        private long	byteCount1;
+        private long	byteCount2;
+
+        internal ulong H1, H2, H3, H4, H5, H6, H7, H8;
+
+        private ulong[] W = new ulong[80];
+        private int wOff;
+
+		/**
+        * Constructor for variable length word
+        */
+        internal LongDigest()
+        {
+            xBuf = new byte[8];
+
+			Reset();
+        }
+
+		/**
+        * Copy constructor.  We are using copy constructors in place
+        * of the object.Clone() interface as this interface is not
+        * supported by J2ME.
+        */
+        internal LongDigest(
+			LongDigest t)
+        {
+            xBuf = new byte[t.xBuf.Length];
+            Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length);
+
+            xBufOff = t.xBufOff;
+            byteCount1 = t.byteCount1;
+            byteCount2 = t.byteCount2;
+
+            H1 = t.H1;
+            H2 = t.H2;
+            H3 = t.H3;
+            H4 = t.H4;
+            H5 = t.H5;
+            H6 = t.H6;
+            H7 = t.H7;
+            H8 = t.H8;
+
+            Array.Copy(t.W, 0, W, 0, t.W.Length);
+            wOff = t.wOff;
+        }
+
+        public void Update(
+            byte input)
+        {
+            xBuf[xBufOff++] = input;
+
+            if (xBufOff == xBuf.Length)
+            {
+                ProcessWord(xBuf, 0);
+                xBufOff = 0;
+            }
+
+            byteCount1++;
+        }
+
+        public void BlockUpdate(
+            byte[]  input,
+            int     inOff,
+            int     length)
+        {
+            //
+            // fill the current word
+            //
+            while ((xBufOff != 0) && (length > 0))
+            {
+                Update(input[inOff]);
+
+                inOff++;
+                length--;
+            }
+
+            //
+            // process whole words.
+            //
+            while (length > xBuf.Length)
+            {
+                ProcessWord(input, inOff);
+
+                inOff += xBuf.Length;
+                length -= xBuf.Length;
+                byteCount1 += xBuf.Length;
+            }
+
+            //
+            // load in the remainder.
+            //
+            while (length > 0)
+            {
+                Update(input[inOff]);
+
+                inOff++;
+                length--;
+            }
+        }
+
+        public void Finish()
+        {
+            AdjustByteCounts();
+
+            long    lowBitLength = byteCount1 << 3;
+            long    hiBitLength = byteCount2;
+
+            //
+            // add the pad bytes.
+            //
+            Update((byte)128);
+
+            while (xBufOff != 0)
+            {
+                Update((byte)0);
+            }
+
+            ProcessLength(lowBitLength, hiBitLength);
+
+            ProcessBlock();
+        }
+
+        public virtual void Reset()
+        {
+            byteCount1 = 0;
+            byteCount2 = 0;
+
+            xBufOff = 0;
+            for ( int i = 0; i < xBuf.Length; i++ )
+            {
+                xBuf[i] = 0;
+            }
+
+            wOff = 0;
+			Array.Clear(W, 0, W.Length);
+        }
+
+        internal void ProcessWord(
+            byte[]  input,
+            int     inOff)
+        {
+			W[wOff] = Pack.BE_To_UInt64(input, inOff);
+
+            if (++wOff == 16)
+            {
+                ProcessBlock();
+            }
+        }
+
+		/**
+        * adjust the byte counts so that byteCount2 represents the
+        * upper long (less 3 bits) word of the byte count.
+        */
+        private void AdjustByteCounts()
+        {
+            if (byteCount1 > 0x1fffffffffffffffL)
+            {
+                byteCount2 += (long) ((ulong) byteCount1 >> 61);
+                byteCount1 &= 0x1fffffffffffffffL;
+            }
+        }
+
+        internal void ProcessLength(
+            long	lowW,
+            long	hiW)
+        {
+            if (wOff > 14)
+            {
+                ProcessBlock();
+            }
+
+            W[14] = (ulong)hiW;
+            W[15] = (ulong)lowW;
+        }
+
+        internal void ProcessBlock()
+        {
+            AdjustByteCounts();
+
+            //
+            // expand 16 word block into 80 word blocks.
+            //
+            for (int ti = 16; ti <= 79; ++ti)
+            {
+                W[ti] = Sigma1(W[ti - 2]) + W[ti - 7] + Sigma0(W[ti - 15]) + W[ti - 16];
+            }
+
+            //
+            // set up working variables.
+            //
+            ulong a = H1;
+            ulong b = H2;
+            ulong c = H3;
+            ulong d = H4;
+            ulong e = H5;
+            ulong f = H6;
+            ulong g = H7;
+            ulong h = H8;
+
+			int t = 0;
+			for(int i = 0; i < 10; i ++)
+			{
+				// t = 8 * i
+				h += Sum1(e) + Ch(e, f, g) + K[t] + W[t++];
+				d += h;
+				h += Sum0(a) + Maj(a, b, c);
+
+				// t = 8 * i + 1
+				g += Sum1(d) + Ch(d, e, f) + K[t] + W[t++];
+				c += g;
+				g += Sum0(h) + Maj(h, a, b);
+
+				// t = 8 * i + 2
+				f += Sum1(c) + Ch(c, d, e) + K[t] + W[t++];
+				b += f;
+				f += Sum0(g) + Maj(g, h, a);
+
+				// t = 8 * i + 3
+				e += Sum1(b) + Ch(b, c, d) + K[t] + W[t++];
+				a += e;
+				e += Sum0(f) + Maj(f, g, h);
+
+				// t = 8 * i + 4
+				d += Sum1(a) + Ch(a, b, c) + K[t] + W[t++];
+				h += d;
+				d += Sum0(e) + Maj(e, f, g);
+
+				// t = 8 * i + 5
+				c += Sum1(h) + Ch(h, a, b) + K[t] + W[t++];
+				g += c;
+				c += Sum0(d) + Maj(d, e, f);
+
+				// t = 8 * i + 6
+				b += Sum1(g) + Ch(g, h, a) + K[t] + W[t++];
+				f += b;
+				b += Sum0(c) + Maj(c, d, e);
+
+				// t = 8 * i + 7
+				a += Sum1(f) + Ch(f, g, h) + K[t] + W[t++];
+				e += a;
+				a += Sum0(b) + Maj(b, c, d);
+			}
+
+			H1 += a;
+            H2 += b;
+            H3 += c;
+            H4 += d;
+            H5 += e;
+            H6 += f;
+            H7 += g;
+            H8 += h;
+
+			//
+            // reset the offset and clean out the word buffer.
+            //
+            wOff = 0;
+			Array.Clear(W, 0, 16);
+		}
+
+		/* SHA-384 and SHA-512 functions (as for SHA-256 but for longs) */
+        private static ulong Ch(ulong x, ulong y, ulong z)
+        {
+            return (x & y) ^ (~x & z);
+        }
+
+        private static ulong Maj(ulong x, ulong y, ulong z)
+        {
+            return (x & y) ^ (x & z) ^ (y & z);
+        }
+
+        private static ulong Sum0(ulong x)
+        {
+	        return ((x << 36) | (x >> 28)) ^ ((x << 30) | (x >> 34)) ^ ((x << 25) | (x >> 39));
+        }
+
+		private static ulong Sum1(ulong x)
+        {
+	        return ((x << 50) | (x >> 14)) ^ ((x << 46) | (x >> 18)) ^ ((x << 23) | (x >> 41));
+        }
+
+        private static ulong Sigma0(ulong x)
+        {
+	        return ((x << 63) | (x >> 1)) ^ ((x << 56) | (x >> 8)) ^ (x >> 7);
+        }
+
+        private static ulong Sigma1(ulong x)
+        {
+	        return ((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6);
+        }
+
+        /* SHA-384 and SHA-512 Constants
+         * (represent the first 64 bits of the fractional parts of the
+         * cube roots of the first sixty-four prime numbers)
+         */
+		internal static readonly ulong[] K =
+		{
+			0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
+			0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
+			0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
+			0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
+			0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
+			0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
+			0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
+			0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
+			0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
+			0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
+			0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
+			0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
+			0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
+			0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
+			0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
+			0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
+			0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
+			0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
+			0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
+			0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817
+		};
+
+		public int GetByteLength()
+		{
+			return MyByteLength;
+		}
+
+		public abstract string AlgorithmName { get; }
+		public abstract int GetDigestSize();
+        public abstract int DoFinal(byte[] output, int outOff);
+    }
+}
diff --git a/Crypto/src/crypto/digests/MD2Digest.cs b/Crypto/src/crypto/digests/MD2Digest.cs
new file mode 100644
index 000000000..78c696f33
--- /dev/null
+++ b/Crypto/src/crypto/digests/MD2Digest.cs
@@ -0,0 +1,247 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+
+    /**
+    * implementation of MD2
+    * as outlined in RFC1319 by B.Kaliski from RSA Laboratories April 1992
+    */
+    public class MD2Digest
+		: IDigest
+    {
+        private const int DigestLength = 16;
+        private const int BYTE_LENGTH = 16;
+
+        /* X buffer */
+        private byte[]   X = new byte[48];
+        private int     xOff;
+
+        /* M buffer */
+
+        private byte[]   M = new byte[16];
+        private int     mOff;
+
+        /* check sum */
+
+        private byte[]   C = new byte[16];
+        private int COff;
+
+        public MD2Digest()
+        {
+            Reset();
+        }
+        public MD2Digest(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);
+            mOff = t.mOff;
+            Array.Copy(t.C, 0, C, 0, t.C.Length);
+            COff = t.COff;
+        }
+        /**
+        * return the algorithm name
+        *
+        * @return the algorithm name
+        */
+        public string AlgorithmName
+		{
+			get { return "MD2"; }
+		}
+
+		public int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		public int GetByteLength()
+		{
+			return BYTE_LENGTH;
+		}
+
+		/**
+        * Close the digest, producing the final digest value. The doFinal
+        * call leaves the digest reset.
+        *
+        * @param out the array the digest is to be copied into.
+        * @param outOff the offset into the out array the digest is to start at.
+        */
+        public int DoFinal(byte[] output, int outOff)
+        {
+            // add padding
+            byte paddingByte = (byte)(M.Length - mOff);
+            for (int i=mOff;i<M.Length;i++)
+            {
+                M[i] = paddingByte;
+            }
+            //do final check sum
+            ProcessChecksum(M);
+            // do final block process
+            ProcessBlock(M);
+
+            ProcessBlock(C);
+
+            Array.Copy(X, xOff, output, outOff, 16);
+
+            Reset();
+
+            return DigestLength;
+        }
+
+        /**
+        * reset the digest back to it's initial state.
+        */
+        public void Reset()
+        {
+            xOff = 0;
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+            mOff = 0;
+            for (int i = 0; i != M.Length; i++)
+            {
+                M[i] = 0;
+            }
+            COff = 0;
+            for (int i = 0; i != C.Length; i++)
+            {
+                C[i] = 0;
+            }
+        }
+        /**
+        * update the message digest with a single byte.
+        *
+        * @param in the input byte to be entered.
+        */
+        public void Update(byte input)
+        {
+            M[mOff++] = input;
+
+            if (mOff == 16)
+            {
+                ProcessChecksum(M);
+                ProcessBlock(M);
+                mOff = 0;
+            }
+        }
+
+        /**
+        * update the message digest with a block of bytes.
+        *
+        * @param in the byte array containing the data.
+        * @param inOff the offset into the byte array where the data starts.
+        * @param len the length of the data.
+        */
+        public void BlockUpdate(byte[] input, int inOff, int length)
+        {
+            //
+            // fill the current word
+            //
+            while ((mOff != 0) && (length > 0))
+            {
+                Update(input[inOff]);
+                inOff++;
+                length--;
+            }
+
+            //
+            // process whole words.
+            //
+            while (length > 16)
+            {
+                Array.Copy(input,inOff,M,0,16);
+                ProcessChecksum(M);
+                ProcessBlock(M);
+                length -= 16;
+                inOff += 16;
+            }
+
+            //
+            // load in the remainder.
+            //
+            while (length > 0)
+            {
+                Update(input[inOff]);
+                inOff++;
+                length--;
+            }
+        }
+
+        internal void ProcessChecksum(byte[] m)
+        {
+            int L = C[15];
+            for (int i=0;i<16;i++)
+            {
+                C[i] ^= S[(m[i] ^ L) & 0xff];
+                L = C[i];
+            }
+        }
+        internal void ProcessBlock(byte[] m)
+        {
+            for (int i=0;i<16;i++)
+            {
+                X[i+16] = m[i];
+                X[i+32] = (byte)(m[i] ^ X[i]);
+            }
+            // encrypt block
+            int t = 0;
+
+            for (int j=0;j<18;j++)
+            {
+                for (int k=0;k<48;k++)
+                {
+                    t = X[k] ^= S[t];
+                    t = t & 0xff;
+                }
+                t = (t + j)%256;
+            }
+        }
+
+
+
+        // 256-byte random permutation constructed from the digits of PI
+        private static readonly byte[] S = {
+        (byte)41,(byte)46,(byte)67,(byte)201,(byte)162,(byte)216,(byte)124,
+        (byte)1,(byte)61,(byte)54,(byte)84,(byte)161,(byte)236,(byte)240,
+        (byte)6,(byte)19,(byte)98,(byte)167,(byte)5,(byte)243,(byte)192,
+        (byte)199,(byte)115,(byte)140,(byte)152,(byte)147,(byte)43,(byte)217,
+        (byte)188,(byte)76,(byte)130,(byte)202,(byte)30,(byte)155,(byte)87,
+        (byte)60,(byte)253,(byte)212,(byte)224,(byte)22,(byte)103,(byte)66,
+        (byte)111,(byte)24,(byte)138,(byte)23,(byte)229,(byte)18,(byte)190,
+        (byte)78,(byte)196,(byte)214,(byte)218,(byte)158,(byte)222,(byte)73,
+        (byte)160,(byte)251,(byte)245,(byte)142,(byte)187,(byte)47,(byte)238,
+        (byte)122,(byte)169,(byte)104,(byte)121,(byte)145,(byte)21,(byte)178,
+        (byte)7,(byte)63,(byte)148,(byte)194,(byte)16,(byte)137,(byte)11,
+        (byte)34,(byte)95,(byte)33,(byte)128,(byte)127,(byte)93,(byte)154,
+        (byte)90,(byte)144,(byte)50,(byte)39,(byte)53,(byte)62,(byte)204,
+        (byte)231,(byte)191,(byte)247,(byte)151,(byte)3,(byte)255,(byte)25,
+        (byte)48,(byte)179,(byte)72,(byte)165,(byte)181,(byte)209,(byte)215,
+        (byte)94,(byte)146,(byte)42,(byte)172,(byte)86,(byte)170,(byte)198,
+        (byte)79,(byte)184,(byte)56,(byte)210,(byte)150,(byte)164,(byte)125,
+        (byte)182,(byte)118,(byte)252,(byte)107,(byte)226,(byte)156,(byte)116,
+        (byte)4,(byte)241,(byte)69,(byte)157,(byte)112,(byte)89,(byte)100,
+        (byte)113,(byte)135,(byte)32,(byte)134,(byte)91,(byte)207,(byte)101,
+        (byte)230,(byte)45,(byte)168,(byte)2,(byte)27,(byte)96,(byte)37,
+        (byte)173,(byte)174,(byte)176,(byte)185,(byte)246,(byte)28,(byte)70,
+        (byte)97,(byte)105,(byte)52,(byte)64,(byte)126,(byte)15,(byte)85,
+        (byte)71,(byte)163,(byte)35,(byte)221,(byte)81,(byte)175,(byte)58,
+        (byte)195,(byte)92,(byte)249,(byte)206,(byte)186,(byte)197,(byte)234,
+        (byte)38,(byte)44,(byte)83,(byte)13,(byte)110,(byte)133,(byte)40,
+        (byte)132, 9,(byte)211,(byte)223,(byte)205,(byte)244,(byte)65,
+        (byte)129,(byte)77,(byte)82,(byte)106,(byte)220,(byte)55,(byte)200,
+        (byte)108,(byte)193,(byte)171,(byte)250,(byte)36,(byte)225,(byte)123,
+        (byte)8,(byte)12,(byte)189,(byte)177,(byte)74,(byte)120,(byte)136,
+        (byte)149,(byte)139,(byte)227,(byte)99,(byte)232,(byte)109,(byte)233,
+        (byte)203,(byte)213,(byte)254,(byte)59,(byte)0,(byte)29,(byte)57,
+        (byte)242,(byte)239,(byte)183,(byte)14,(byte)102,(byte)88,(byte)208,
+        (byte)228,(byte)166,(byte)119,(byte)114,(byte)248,(byte)235,(byte)117,
+        (byte)75,(byte)10,(byte)49,(byte)68,(byte)80,(byte)180,(byte)143,
+        (byte)237,(byte)31,(byte)26,(byte)219,(byte)153,(byte)141,(byte)51,
+        (byte)159,(byte)17,(byte)131,(byte)20
+        };
+    }
+
+}
diff --git a/Crypto/src/crypto/digests/MD4Digest.cs b/Crypto/src/crypto/digests/MD4Digest.cs
new file mode 100644
index 000000000..bc4eae0fd
--- /dev/null
+++ b/Crypto/src/crypto/digests/MD4Digest.cs
@@ -0,0 +1,271 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /**
+    * implementation of MD4 as RFC 1320 by R. Rivest, MIT Laboratory for
+    * Computer Science and RSA Data Security, Inc.
+    * <p>
+    * <b>NOTE</b>: This algorithm is only included for backwards compatibility
+    * with legacy applications, it's not secure, don't use it for anything new!</p>
+    */
+    public class MD4Digest
+		: GeneralDigest
+    {
+        private const int    DigestLength = 16;
+
+        private int     H1, H2, H3, H4;         // IV's
+
+        private int[]   X = new int[16];
+        private int     xOff;
+
+        /**
+        * Standard constructor
+        */
+        public MD4Digest()
+        {
+            Reset();
+        }
+
+        /**
+        * Copy constructor.  This will copy the state of the provided
+        * message digest.
+        */
+        public MD4Digest(MD4Digest t) : base(t)
+        {
+            H1 = t.H1;
+            H2 = t.H2;
+            H3 = t.H3;
+            H4 = t.H4;
+
+            Array.Copy(t.X, 0, X, 0, t.X.Length);
+            xOff = t.xOff;
+        }
+
+		public override string AlgorithmName
+		{
+			get { return "MD4"; }
+		}
+
+		public override int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		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);
+
+            if (xOff == 16)
+            {
+                ProcessBlock();
+            }
+        }
+
+        internal override void ProcessLength(
+            long    bitLength)
+        {
+            if (xOff > 14)
+            {
+                ProcessBlock();
+            }
+
+            X[14] = (int)(bitLength & 0xffffffff);
+            X[15] = (int)((ulong) bitLength >> 32);
+        }
+
+        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);
+        }
+
+        public override int DoFinal(
+            byte[]  output,
+            int     outOff)
+        {
+            Finish();
+
+            UnpackWord(H1, output, outOff);
+            UnpackWord(H2, output, outOff + 4);
+            UnpackWord(H3, output, outOff + 8);
+            UnpackWord(H4, output, outOff + 12);
+
+            Reset();
+
+            return DigestLength;
+        }
+
+        /**
+        * reset the chaining variables to the IV values.
+        */
+        public override void Reset()
+        {
+            base.Reset();
+
+            H1 = unchecked((int) 0x67452301);
+            H2 = unchecked((int) 0xefcdab89);
+            H3 = unchecked((int) 0x98badcfe);
+            H4 = unchecked((int) 0x10325476);
+
+            xOff = 0;
+
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+        }
+
+        //
+        // round 1 left rotates
+        //
+        private const int S11 = 3;
+        private const int S12 = 7;
+        private const int S13 = 11;
+        private const int S14 = 19;
+
+        //
+        // round 2 left rotates
+        //
+        private const int S21 = 3;
+        private const int S22 = 5;
+        private const int S23 = 9;
+        private const int S24 = 13;
+
+        //
+        // round 3 left rotates
+        //
+        private const int S31 = 3;
+        private const int S32 = 9;
+        private const int S33 = 11;
+        private const int S34 = 15;
+
+        /*
+        * rotate int x left n bits.
+        */
+        private int RotateLeft(
+            int x,
+            int n)
+        {
+            return (x << n) | (int) ((uint) x >> (32 - n));
+        }
+
+        /*
+        * F, G, H and I are the basic MD4 functions.
+        */
+        private int F(
+            int u,
+            int v,
+            int w)
+        {
+            return (u & v) | (~u & w);
+        }
+
+        private int G(
+            int u,
+            int v,
+            int w)
+        {
+            return (u & v) | (u & w) | (v & w);
+        }
+
+        private int H(
+            int u,
+            int v,
+            int w)
+        {
+            return u ^ v ^ w;
+        }
+
+        internal override void ProcessBlock()
+        {
+            int a = H1;
+            int b = H2;
+            int c = H3;
+            int d = H4;
+
+            //
+            // Round 1 - F cycle, 16 times.
+            //
+            a = RotateLeft((a + F(b, c, d) + X[ 0]), S11);
+            d = RotateLeft((d + F(a, b, c) + X[ 1]), S12);
+            c = RotateLeft((c + F(d, a, b) + X[ 2]), S13);
+            b = RotateLeft((b + F(c, d, a) + X[ 3]), S14);
+            a = RotateLeft((a + F(b, c, d) + X[ 4]), S11);
+            d = RotateLeft((d + F(a, b, c) + X[ 5]), S12);
+            c = RotateLeft((c + F(d, a, b) + X[ 6]), S13);
+            b = RotateLeft((b + F(c, d, a) + X[ 7]), S14);
+            a = RotateLeft((a + F(b, c, d) + X[ 8]), S11);
+            d = RotateLeft((d + F(a, b, c) + X[ 9]), S12);
+            c = RotateLeft((c + F(d, a, b) + X[10]), S13);
+            b = RotateLeft((b + F(c, d, a) + X[11]), S14);
+            a = RotateLeft((a + F(b, c, d) + X[12]), S11);
+            d = RotateLeft((d + F(a, b, c) + X[13]), S12);
+            c = RotateLeft((c + F(d, a, b) + X[14]), S13);
+            b = RotateLeft((b + F(c, d, a) + X[15]), S14);
+
+            //
+            // Round 2 - G cycle, 16 times.
+            //
+            a = RotateLeft((a + G(b, c, d) + X[ 0] + 0x5a827999), S21);
+            d = RotateLeft((d + G(a, b, c) + X[ 4] + 0x5a827999), S22);
+            c = RotateLeft((c + G(d, a, b) + X[ 8] + 0x5a827999), S23);
+            b = RotateLeft((b + G(c, d, a) + X[12] + 0x5a827999), S24);
+            a = RotateLeft((a + G(b, c, d) + X[ 1] + 0x5a827999), S21);
+            d = RotateLeft((d + G(a, b, c) + X[ 5] + 0x5a827999), S22);
+            c = RotateLeft((c + G(d, a, b) + X[ 9] + 0x5a827999), S23);
+            b = RotateLeft((b + G(c, d, a) + X[13] + 0x5a827999), S24);
+            a = RotateLeft((a + G(b, c, d) + X[ 2] + 0x5a827999), S21);
+            d = RotateLeft((d + G(a, b, c) + X[ 6] + 0x5a827999), S22);
+            c = RotateLeft((c + G(d, a, b) + X[10] + 0x5a827999), S23);
+            b = RotateLeft((b + G(c, d, a) + X[14] + 0x5a827999), S24);
+            a = RotateLeft((a + G(b, c, d) + X[ 3] + 0x5a827999), S21);
+            d = RotateLeft((d + G(a, b, c) + X[ 7] + 0x5a827999), S22);
+            c = RotateLeft((c + G(d, a, b) + X[11] + 0x5a827999), S23);
+            b = RotateLeft((b + G(c, d, a) + X[15] + 0x5a827999), S24);
+
+            //
+            // Round 3 - H cycle, 16 times.
+            //
+            a = RotateLeft((a + H(b, c, d) + X[ 0] + 0x6ed9eba1), S31);
+            d = RotateLeft((d + H(a, b, c) + X[ 8] + 0x6ed9eba1), S32);
+            c = RotateLeft((c + H(d, a, b) + X[ 4] + 0x6ed9eba1), S33);
+            b = RotateLeft((b + H(c, d, a) + X[12] + 0x6ed9eba1), S34);
+            a = RotateLeft((a + H(b, c, d) + X[ 2] + 0x6ed9eba1), S31);
+            d = RotateLeft((d + H(a, b, c) + X[10] + 0x6ed9eba1), S32);
+            c = RotateLeft((c + H(d, a, b) + X[ 6] + 0x6ed9eba1), S33);
+            b = RotateLeft((b + H(c, d, a) + X[14] + 0x6ed9eba1), S34);
+            a = RotateLeft((a + H(b, c, d) + X[ 1] + 0x6ed9eba1), S31);
+            d = RotateLeft((d + H(a, b, c) + X[ 9] + 0x6ed9eba1), S32);
+            c = RotateLeft((c + H(d, a, b) + X[ 5] + 0x6ed9eba1), S33);
+            b = RotateLeft((b + H(c, d, a) + X[13] + 0x6ed9eba1), S34);
+            a = RotateLeft((a + H(b, c, d) + X[ 3] + 0x6ed9eba1), S31);
+            d = RotateLeft((d + H(a, b, c) + X[11] + 0x6ed9eba1), S32);
+            c = RotateLeft((c + H(d, a, b) + X[ 7] + 0x6ed9eba1), S33);
+            b = RotateLeft((b + H(c, d, a) + X[15] + 0x6ed9eba1), S34);
+
+            H1 += a;
+            H2 += b;
+            H3 += c;
+            H4 += d;
+
+            //
+            // reset the offset and clean out the word buffer.
+            //
+            xOff = 0;
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+        }
+    }
+
+}
diff --git a/Crypto/src/crypto/digests/MD5Digest.cs b/Crypto/src/crypto/digests/MD5Digest.cs
new file mode 100644
index 000000000..50d93e4f8
--- /dev/null
+++ b/Crypto/src/crypto/digests/MD5Digest.cs
@@ -0,0 +1,301 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /**
+    * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
+    */
+    public class MD5Digest
+		: GeneralDigest
+    {
+        private const int DigestLength = 16;
+
+        private int H1, H2, H3, H4;         // IV's
+
+        private int[]	X = new int[16];
+        private int		xOff;
+
+        public MD5Digest()
+        {
+            Reset();
+        }
+
+        /**
+        * Copy constructor.  This will copy the state of the provided
+        * message digest.
+        */
+        public MD5Digest(MD5Digest t)
+			: base(t)
+        {
+            H1 = t.H1;
+            H2 = t.H2;
+            H3 = t.H3;
+            H4 = t.H4;
+
+            Array.Copy(t.X, 0, X, 0, t.X.Length);
+            xOff = t.xOff;
+        }
+
+		public override string AlgorithmName
+		{
+			get { return "MD5"; }
+		}
+
+		public override int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		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);
+
+            if (xOff == 16)
+            {
+                ProcessBlock();
+            }
+        }
+
+        internal override void ProcessLength(
+            long    bitLength)
+        {
+            if (xOff > 14)
+            {
+                ProcessBlock();
+            }
+
+            X[14] = (int)(bitLength & 0xffffffff);
+            X[15] = (int)((ulong) bitLength >> 32);
+        }
+
+        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);
+        }
+
+        public override int DoFinal(
+            byte[]  output,
+            int     outOff)
+        {
+            Finish();
+
+            UnpackWord(H1, output, outOff);
+            UnpackWord(H2, output, outOff + 4);
+            UnpackWord(H3, output, outOff + 8);
+            UnpackWord(H4, output, outOff + 12);
+
+            Reset();
+
+            return DigestLength;
+        }
+
+        /**
+        * reset the chaining variables to the IV values.
+        */
+        public override void Reset()
+        {
+            base.Reset();
+
+            H1 = unchecked((int) 0x67452301);
+            H2 = unchecked((int) 0xefcdab89);
+            H3 = unchecked((int) 0x98badcfe);
+            H4 = unchecked((int) 0x10325476);
+
+            xOff = 0;
+
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+        }
+
+        //
+        // round 1 left rotates
+        //
+        private static readonly int S11 = 7;
+        private static readonly int S12 = 12;
+        private static readonly int S13 = 17;
+        private static readonly int S14 = 22;
+
+        //
+        // round 2 left rotates
+        //
+        private static readonly int S21 = 5;
+        private static readonly int S22 = 9;
+        private static readonly int S23 = 14;
+        private static readonly int S24 = 20;
+
+        //
+        // round 3 left rotates
+        //
+        private static readonly int S31 = 4;
+        private static readonly int S32 = 11;
+        private static readonly int S33 = 16;
+        private static readonly int S34 = 23;
+
+        //
+        // round 4 left rotates
+        //
+        private static readonly int S41 = 6;
+        private static readonly int S42 = 10;
+        private static readonly int S43 = 15;
+        private static readonly int S44 = 21;
+
+        /*
+        * rotate int x left n bits.
+        */
+        private int RotateLeft(
+            int x,
+            int n)
+        {
+            return (x << n) | (int) ((uint) x >> (32 - n));
+        }
+
+        /*
+        * F, G, H and I are the basic MD5 functions.
+        */
+        private int F(
+            int u,
+            int v,
+            int w)
+        {
+            return (u & v) | (~u & w);
+        }
+
+        private int G(
+            int u,
+            int v,
+            int w)
+        {
+            return (u & w) | (v & ~w);
+        }
+
+        private int H(
+            int u,
+            int v,
+            int w)
+        {
+            return u ^ v ^ w;
+        }
+
+        private int K(
+            int u,
+            int v,
+            int w)
+        {
+            return v ^ (u | ~w);
+        }
+
+        internal override void ProcessBlock()
+        {
+            int a = H1;
+            int b = H2;
+            int c = H3;
+            int d = H4;
+
+            //
+            // Round 1 - F cycle, 16 times.
+            //
+            a = RotateLeft((a + F(b, c, d) + X[ 0] + 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;
+
+            //
+            // 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;
+
+            //
+            // 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;
+
+            //
+            // 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;
+
+            H1 += a;
+            H2 += b;
+            H3 += c;
+            H4 += d;
+
+            //
+            // reset the offset and clean out the word buffer.
+            //
+            xOff = 0;
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+        }
+    }
+
+}
diff --git a/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
new file mode 100644
index 000000000..8977583a4
--- /dev/null
+++ b/Crypto/src/crypto/digests/RipeMD128Digest.cs
@@ -0,0 +1,462 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /**
+    * implementation of RipeMD128
+    */
+    public class RipeMD128Digest
+		: GeneralDigest
+    {
+        private const int DigestLength = 16;
+
+        private int H0, H1, H2, H3; // IV's
+
+        private int[] X = new int[16];
+        private int xOff;
+
+        /**
+        * Standard constructor
+        */
+        public RipeMD128Digest()
+        {
+            Reset();
+        }
+
+        /**
+        * Copy constructor.  This will copy the state of the provided
+        * message digest.
+        */
+        public RipeMD128Digest(RipeMD128Digest t) : base(t)
+        {
+            H0 = t.H0;
+            H1 = t.H1;
+            H2 = t.H2;
+            H3 = t.H3;
+
+            Array.Copy(t.X, 0, X, 0, t.X.Length);
+            xOff = t.xOff;
+        }
+
+		public override string AlgorithmName
+		{
+			get { return "RIPEMD128"; }
+		}
+
+		public override int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		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);
+
+            if (xOff == 16)
+            {
+                ProcessBlock();
+            }
+        }
+
+        internal override void ProcessLength(
+            long bitLength)
+        {
+            if (xOff > 14)
+            {
+            ProcessBlock();
+            }
+
+            X[14] = (int)(bitLength & 0xffffffff);
+            X[15] = (int)((ulong) bitLength >> 32);
+        }
+
+        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);
+        }
+
+        public override int DoFinal(
+            byte[] output,
+            int outOff)
+        {
+            Finish();
+
+            UnpackWord(H0, output, outOff);
+            UnpackWord(H1, output, outOff + 4);
+            UnpackWord(H2, output, outOff + 8);
+            UnpackWord(H3, output, outOff + 12);
+
+            Reset();
+
+            return DigestLength;
+        }
+
+        /**
+        * reset the chaining variables to the IV values.
+        */
+        public override void Reset()
+        {
+            base.Reset();
+
+            H0 = unchecked((int) 0x67452301);
+            H1 = unchecked((int) 0xefcdab89);
+            H2 = unchecked((int) 0x98badcfe);
+            H3 = unchecked((int) 0x10325476);
+
+            xOff = 0;
+
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+        }
+
+        /*
+        * rotate int x left n bits.
+        */
+        private int RL(
+            int x,
+            int n)
+        {
+            return (x << n) | (int) ((uint) x >> (32 - n));
+        }
+
+        /*
+        * f1,f2,f3,f4 are the basic RipeMD128 functions.
+        */
+
+        /*
+        * F
+        */
+        private int F1(
+            int x,
+            int y,
+            int z)
+        {
+            return x ^ y ^ z;
+        }
+
+        /*
+        * G
+        */
+        private int F2(
+            int x,
+            int y,
+            int z)
+        {
+            return (x & y) | (~x & z);
+        }
+
+        /*
+        * H
+        */
+        private int F3(
+            int x,
+            int y,
+            int z)
+        {
+            return (x | ~y) ^ z;
+        }
+
+        /*
+        * I
+        */
+        private int F4(
+            int x,
+            int y,
+            int z)
+        {
+            return (x & z) | (y & ~z);
+        }
+
+        private int F1(
+            int a,
+            int b,
+            int c,
+            int d,
+            int x,
+            int s)
+        {
+            return RL(a + F1(b, c, d) + x, s);
+        }
+
+        private int F2(
+            int a,
+            int b,
+            int c,
+            int d,
+            int x,
+            int s)
+        {
+            return RL(a + F2(b, c, d) + x + unchecked((int) 0x5a827999), s);
+        }
+
+        private int F3(
+            int a,
+            int b,
+            int c,
+            int d,
+            int x,
+            int s)
+        {
+            return RL(a + F3(b, c, d) + x + unchecked((int) 0x6ed9eba1), s);
+        }
+
+        private int F4(
+            int a,
+            int b,
+            int c,
+            int d,
+            int x,
+            int s)
+        {
+            return RL(a + F4(b, c, d) + x + unchecked((int) 0x8f1bbcdc), s);
+        }
+
+        private int FF1(
+            int a,
+            int b,
+            int c,
+            int d,
+            int x,
+            int s)
+        {
+            return RL(a + F1(b, c, d) + x, s);
+        }
+
+        private int FF2(
+            int a,
+            int b,
+            int c,
+            int d,
+            int x,
+            int s)
+        {
+        return RL(a + F2(b, c, d) + x + unchecked((int) 0x6d703ef3), s);
+        }
+
+        private int FF3(
+            int a,
+            int b,
+            int c,
+            int d,
+            int x,
+            int s)
+        {
+        return RL(a + F3(b, c, d) + x + unchecked((int) 0x5c4dd124), s);
+        }
+
+        private int FF4(
+            int a,
+            int b,
+            int c,
+            int d,
+            int x,
+            int s)
+        {
+        return RL(a + F4(b, c, d) + x + unchecked((int) 0x50a28be6), s);
+        }
+
+        internal override void ProcessBlock()
+        {
+            int a, aa;
+            int b, bb;
+            int c, cc;
+            int d, dd;
+
+            a = aa = H0;
+            b = bb = H1;
+            c = cc = H2;
+            d = dd = H3;
+
+            //
+            // Round 1
+            //
+            a = F1(a, b, c, d, X[ 0], 11);
+            d = F1(d, a, b, c, X[ 1], 14);
+            c = F1(c, d, a, b, X[ 2], 15);
+            b = F1(b, c, d, a, X[ 3], 12);
+            a = F1(a, b, c, d, X[ 4],  5);
+            d = F1(d, a, b, c, X[ 5],  8);
+            c = F1(c, d, a, b, X[ 6],  7);
+            b = F1(b, c, d, a, X[ 7],  9);
+            a = F1(a, b, c, d, X[ 8], 11);
+            d = F1(d, a, b, c, X[ 9], 13);
+            c = F1(c, d, a, b, X[10], 14);
+            b = F1(b, c, d, a, X[11], 15);
+            a = F1(a, b, c, d, X[12],  6);
+            d = F1(d, a, b, c, X[13],  7);
+            c = F1(c, d, a, b, X[14],  9);
+            b = F1(b, c, d, a, X[15],  8);
+
+            //
+            // Round 2
+            //
+            a = F2(a, b, c, d, X[ 7],  7);
+            d = F2(d, a, b, c, X[ 4],  6);
+            c = F2(c, d, a, b, X[13],  8);
+            b = F2(b, c, d, a, X[ 1], 13);
+            a = F2(a, b, c, d, X[10], 11);
+            d = F2(d, a, b, c, X[ 6],  9);
+            c = F2(c, d, a, b, X[15],  7);
+            b = F2(b, c, d, a, X[ 3], 15);
+            a = F2(a, b, c, d, X[12],  7);
+            d = F2(d, a, b, c, X[ 0], 12);
+            c = F2(c, d, a, b, X[ 9], 15);
+            b = F2(b, c, d, a, X[ 5],  9);
+            a = F2(a, b, c, d, X[ 2], 11);
+            d = F2(d, a, b, c, X[14],  7);
+            c = F2(c, d, a, b, X[11], 13);
+            b = F2(b, c, d, a, X[ 8], 12);
+
+            //
+            // Round 3
+            //
+            a = F3(a, b, c, d, X[ 3], 11);
+            d = F3(d, a, b, c, X[10], 13);
+            c = F3(c, d, a, b, X[14],  6);
+            b = F3(b, c, d, a, X[ 4],  7);
+            a = F3(a, b, c, d, X[ 9], 14);
+            d = F3(d, a, b, c, X[15],  9);
+            c = F3(c, d, a, b, X[ 8], 13);
+            b = F3(b, c, d, a, X[ 1], 15);
+            a = F3(a, b, c, d, X[ 2], 14);
+            d = F3(d, a, b, c, X[ 7],  8);
+            c = F3(c, d, a, b, X[ 0], 13);
+            b = F3(b, c, d, a, X[ 6],  6);
+            a = F3(a, b, c, d, X[13],  5);
+            d = F3(d, a, b, c, X[11], 12);
+            c = F3(c, d, a, b, X[ 5],  7);
+            b = F3(b, c, d, a, X[12],  5);
+
+            //
+            // Round 4
+            //
+            a = F4(a, b, c, d, X[ 1], 11);
+            d = F4(d, a, b, c, X[ 9], 12);
+            c = F4(c, d, a, b, X[11], 14);
+            b = F4(b, c, d, a, X[10], 15);
+            a = F4(a, b, c, d, X[ 0], 14);
+            d = F4(d, a, b, c, X[ 8], 15);
+            c = F4(c, d, a, b, X[12],  9);
+            b = F4(b, c, d, a, X[ 4],  8);
+            a = F4(a, b, c, d, X[13],  9);
+            d = F4(d, a, b, c, X[ 3], 14);
+            c = F4(c, d, a, b, X[ 7],  5);
+            b = F4(b, c, d, a, X[15],  6);
+            a = F4(a, b, c, d, X[14],  8);
+            d = F4(d, a, b, c, X[ 5],  6);
+            c = F4(c, d, a, b, X[ 6],  5);
+            b = F4(b, c, d, a, X[ 2], 12);
+
+            //
+            // Parallel round 1
+            //
+            aa = FF4(aa, bb, cc, dd, X[ 5],  8);
+            dd = FF4(dd, aa, bb, cc, X[14],  9);
+            cc = FF4(cc, dd, aa, bb, X[ 7],  9);
+            bb = FF4(bb, cc, dd, aa, X[ 0], 11);
+            aa = FF4(aa, bb, cc, dd, X[ 9], 13);
+            dd = FF4(dd, aa, bb, cc, X[ 2], 15);
+            cc = FF4(cc, dd, aa, bb, X[11], 15);
+            bb = FF4(bb, cc, dd, aa, X[ 4],  5);
+            aa = FF4(aa, bb, cc, dd, X[13],  7);
+            dd = FF4(dd, aa, bb, cc, X[ 6],  7);
+            cc = FF4(cc, dd, aa, bb, X[15],  8);
+            bb = FF4(bb, cc, dd, aa, X[ 8], 11);
+            aa = FF4(aa, bb, cc, dd, X[ 1], 14);
+            dd = FF4(dd, aa, bb, cc, X[10], 14);
+            cc = FF4(cc, dd, aa, bb, X[ 3], 12);
+            bb = FF4(bb, cc, dd, aa, X[12],  6);
+
+            //
+            // Parallel round 2
+            //
+            aa = FF3(aa, bb, cc, dd, X[ 6],  9);
+            dd = FF3(dd, aa, bb, cc, X[11], 13);
+            cc = FF3(cc, dd, aa, bb, X[ 3], 15);
+            bb = FF3(bb, cc, dd, aa, X[ 7],  7);
+            aa = FF3(aa, bb, cc, dd, X[ 0], 12);
+            dd = FF3(dd, aa, bb, cc, X[13],  8);
+            cc = FF3(cc, dd, aa, bb, X[ 5],  9);
+            bb = FF3(bb, cc, dd, aa, X[10], 11);
+            aa = FF3(aa, bb, cc, dd, X[14],  7);
+            dd = FF3(dd, aa, bb, cc, X[15],  7);
+            cc = FF3(cc, dd, aa, bb, X[ 8], 12);
+            bb = FF3(bb, cc, dd, aa, X[12],  7);
+            aa = FF3(aa, bb, cc, dd, X[ 4],  6);
+            dd = FF3(dd, aa, bb, cc, X[ 9], 15);
+            cc = FF3(cc, dd, aa, bb, X[ 1], 13);
+            bb = FF3(bb, cc, dd, aa, X[ 2], 11);
+
+            //
+            // Parallel round 3
+            //
+            aa = FF2(aa, bb, cc, dd, X[15],  9);
+            dd = FF2(dd, aa, bb, cc, X[ 5],  7);
+            cc = FF2(cc, dd, aa, bb, X[ 1], 15);
+            bb = FF2(bb, cc, dd, aa, X[ 3], 11);
+            aa = FF2(aa, bb, cc, dd, X[ 7],  8);
+            dd = FF2(dd, aa, bb, cc, X[14],  6);
+            cc = FF2(cc, dd, aa, bb, X[ 6],  6);
+            bb = FF2(bb, cc, dd, aa, X[ 9], 14);
+            aa = FF2(aa, bb, cc, dd, X[11], 12);
+            dd = FF2(dd, aa, bb, cc, X[ 8], 13);
+            cc = FF2(cc, dd, aa, bb, X[12],  5);
+            bb = FF2(bb, cc, dd, aa, X[ 2], 14);
+            aa = FF2(aa, bb, cc, dd, X[10], 13);
+            dd = FF2(dd, aa, bb, cc, X[ 0], 13);
+            cc = FF2(cc, dd, aa, bb, X[ 4],  7);
+            bb = FF2(bb, cc, dd, aa, X[13],  5);
+
+            //
+            // Parallel round 4
+            //
+            aa = FF1(aa, bb, cc, dd, X[ 8], 15);
+            dd = FF1(dd, aa, bb, cc, X[ 6],  5);
+            cc = FF1(cc, dd, aa, bb, X[ 4],  8);
+            bb = FF1(bb, cc, dd, aa, X[ 1], 11);
+            aa = FF1(aa, bb, cc, dd, X[ 3], 14);
+            dd = FF1(dd, aa, bb, cc, X[11], 14);
+            cc = FF1(cc, dd, aa, bb, X[15],  6);
+            bb = FF1(bb, cc, dd, aa, X[ 0], 14);
+            aa = FF1(aa, bb, cc, dd, X[ 5],  6);
+            dd = FF1(dd, aa, bb, cc, X[12],  9);
+            cc = FF1(cc, dd, aa, bb, X[ 2], 12);
+            bb = FF1(bb, cc, dd, aa, X[13],  9);
+            aa = FF1(aa, bb, cc, dd, X[ 9], 12);
+            dd = FF1(dd, aa, bb, cc, X[ 7],  5);
+            cc = FF1(cc, dd, aa, bb, X[10], 15);
+            bb = FF1(bb, cc, dd, aa, X[14],  8);
+
+            dd += c + H1;               // final result for H0
+
+            //
+            // combine the results
+            //
+            H1 = H2 + d + aa;
+            H2 = H3 + a + bb;
+            H3 = H0 + b + cc;
+            H0 = dd;
+
+            //
+            // reset the offset and clean out the word buffer.
+            //
+            xOff = 0;
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+        }
+    }
+
+}
diff --git a/Crypto/src/crypto/digests/RipeMD160Digest.cs b/Crypto/src/crypto/digests/RipeMD160Digest.cs
new file mode 100644
index 000000000..8ce52ae58
--- /dev/null
+++ b/Crypto/src/crypto/digests/RipeMD160Digest.cs
@@ -0,0 +1,423 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /**
+    * implementation of RipeMD see,
+    * http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
+    */
+    public class RipeMD160Digest
+		: GeneralDigest
+    {
+        private const int DigestLength = 20;
+
+        private int H0, H1, H2, H3, H4; // IV's
+
+        private int[] X = new int[16];
+        private int xOff;
+
+        /**
+        * Standard constructor
+        */
+        public RipeMD160Digest()
+        {
+            Reset();
+        }
+
+        /**
+        * Copy constructor.  This will copy the state of the provided
+        * message digest.
+        */
+        public RipeMD160Digest(RipeMD160Digest t) : base(t)
+        {
+            H0 = t.H0;
+            H1 = t.H1;
+            H2 = t.H2;
+            H3 = t.H3;
+            H4 = t.H4;
+
+            Array.Copy(t.X, 0, X, 0, t.X.Length);
+            xOff = t.xOff;
+        }
+
+        public override string AlgorithmName
+		{
+			get { return "RIPEMD160"; }
+		}
+
+		public override int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		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);
+
+            if (xOff == 16)
+            {
+                ProcessBlock();
+            }
+        }
+
+		internal override void ProcessLength(
+            long bitLength)
+        {
+            if (xOff > 14)
+            {
+            ProcessBlock();
+            }
+
+            X[14] = (int)(bitLength & 0xffffffff);
+            X[15] = (int)((ulong) bitLength >> 32);
+        }
+
+        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);
+        }
+
+        public override int DoFinal(
+            byte[] output,
+            int outOff)
+        {
+            Finish();
+
+            UnpackWord(H0, output, outOff);
+            UnpackWord(H1, output, outOff + 4);
+            UnpackWord(H2, output, outOff + 8);
+            UnpackWord(H3, output, outOff + 12);
+            UnpackWord(H4, output, outOff + 16);
+
+            Reset();
+
+            return DigestLength;
+        }
+
+        /**
+        * reset the chaining variables to the IV values.
+        */
+        public override void Reset()
+        {
+            base.Reset();
+
+            H0 = unchecked((int) 0x67452301);
+            H1 = unchecked((int) 0xefcdab89);
+            H2 = unchecked((int) 0x98badcfe);
+            H3 = unchecked((int) 0x10325476);
+            H4 = unchecked((int) 0xc3d2e1f0);
+
+            xOff = 0;
+
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+        }
+
+        /*
+        * rotate int x left n bits.
+        */
+        private  int RL(
+            int x,
+            int n)
+        {
+            return (x << n) | (int) ((uint) x >> (32 - n));
+        }
+
+        /*
+        * f1,f2,f3,f4,f5 are the basic RipeMD160 functions.
+        */
+
+        /*
+        * rounds 0-15
+        */
+        private  int F1(
+            int x,
+            int y,
+            int z)
+        {
+            return x ^ y ^ z;
+        }
+
+        /*
+        * rounds 16-31
+        */
+        private  int F2(
+            int x,
+            int y,
+            int z)
+        {
+            return (x & y) | (~x & z);
+        }
+
+        /*
+        * rounds 32-47
+        */
+        private  int F3(
+            int x,
+            int y,
+            int z)
+        {
+            return (x | ~y) ^ z;
+        }
+
+        /*
+        * rounds 48-63
+        */
+        private  int F4(
+            int x,
+            int y,
+            int z)
+        {
+            return (x & z) | (y & ~z);
+        }
+
+        /*
+        * rounds 64-79
+        */
+        private  int F5(
+            int x,
+            int y,
+            int z)
+        {
+            return x ^ (y | ~z);
+        }
+
+        internal override void ProcessBlock()
+        {
+            int a, aa;
+            int b, bb;
+            int c, cc;
+            int d, dd;
+            int e, ee;
+
+            a = aa = H0;
+            b = bb = H1;
+            c = cc = H2;
+            d = dd = H3;
+            e = ee = H4;
+
+            //
+            // Rounds 1 - 16
+            //
+            // left
+            a = RL(a + F1(b,c,d) + X[ 0], 11) + e; c = RL(c, 10);
+            e = RL(e + F1(a,b,c) + X[ 1], 14) + d; b = RL(b, 10);
+            d = RL(d + F1(e,a,b) + X[ 2], 15) + c; a = RL(a, 10);
+            c = RL(c + F1(d,e,a) + X[ 3], 12) + b; e = RL(e, 10);
+            b = RL(b + F1(c,d,e) + X[ 4],  5) + a; d = RL(d, 10);
+            a = RL(a + F1(b,c,d) + X[ 5],  8) + e; c = RL(c, 10);
+            e = RL(e + F1(a,b,c) + X[ 6],  7) + d; b = RL(b, 10);
+            d = RL(d + F1(e,a,b) + X[ 7],  9) + c; a = RL(a, 10);
+            c = RL(c + F1(d,e,a) + X[ 8], 11) + b; e = RL(e, 10);
+            b = RL(b + F1(c,d,e) + X[ 9], 13) + a; d = RL(d, 10);
+            a = RL(a + F1(b,c,d) + X[10], 14) + e; c = RL(c, 10);
+            e = RL(e + F1(a,b,c) + X[11], 15) + d; b = RL(b, 10);
+            d = RL(d + F1(e,a,b) + X[12],  6) + c; a = RL(a, 10);
+            c = RL(c + F1(d,e,a) + X[13],  7) + b; e = RL(e, 10);
+            b = RL(b + F1(c,d,e) + X[14],  9) + a; d = RL(d, 10);
+            a = RL(a + F1(b,c,d) + X[15],  8) + e; c = RL(c, 10);
+
+            // right
+            aa = RL(aa + F5(bb,cc,dd) + X[ 5] + unchecked((int) 0x50a28be6),  8) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F5(aa,bb,cc) + X[14] + unchecked((int) 0x50a28be6),  9) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F5(ee,aa,bb) + X[ 7] + unchecked((int) 0x50a28be6),  9) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F5(dd,ee,aa) + X[ 0] + unchecked((int) 0x50a28be6), 11) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F5(cc,dd,ee) + X[ 9] + unchecked((int) 0x50a28be6), 13) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F5(bb,cc,dd) + X[ 2] + unchecked((int) 0x50a28be6), 15) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F5(aa,bb,cc) + X[11] + unchecked((int) 0x50a28be6), 15) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F5(ee,aa,bb) + X[ 4] + unchecked((int) 0x50a28be6),  5) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F5(dd,ee,aa) + X[13] + unchecked((int) 0x50a28be6),  7) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F5(cc,dd,ee) + X[ 6] + unchecked((int) 0x50a28be6),  7) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F5(bb,cc,dd) + X[15] + unchecked((int) 0x50a28be6),  8) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F5(aa,bb,cc) + X[ 8] + unchecked((int) 0x50a28be6), 11) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F5(ee,aa,bb) + X[ 1] + unchecked((int) 0x50a28be6), 14) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F5(dd,ee,aa) + X[10] + unchecked((int) 0x50a28be6), 14) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F5(cc,dd,ee) + X[ 3] + unchecked((int) 0x50a28be6), 12) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F5(bb,cc,dd) + X[12] + unchecked((int) 0x50a28be6),  6) + ee; cc = RL(cc, 10);
+
+            //
+            // Rounds 16-31
+            //
+            // left
+            e = RL(e + F2(a,b,c) + X[ 7] + unchecked((int) 0x5a827999),   7) + d; b = RL(b, 10);
+            d = RL(d + F2(e,a,b) + X[ 4] + unchecked((int) 0x5a827999),   6) + c; a = RL(a, 10);
+            c = RL(c + F2(d,e,a) + X[13] + unchecked((int) 0x5a827999),   8) + b; e = RL(e, 10);
+            b = RL(b + F2(c,d,e) + X[ 1] + unchecked((int) 0x5a827999),  13) + a; d = RL(d, 10);
+            a = RL(a + F2(b,c,d) + X[10] + unchecked((int) 0x5a827999),  11) + e; c = RL(c, 10);
+            e = RL(e + F2(a,b,c) + X[ 6] + unchecked((int) 0x5a827999),   9) + d; b = RL(b, 10);
+            d = RL(d + F2(e,a,b) + X[15] + unchecked((int) 0x5a827999),   7) + c; a = RL(a, 10);
+            c = RL(c + F2(d,e,a) + X[ 3] + unchecked((int) 0x5a827999),  15) + b; e = RL(e, 10);
+            b = RL(b + F2(c,d,e) + X[12] + unchecked((int) 0x5a827999),   7) + a; d = RL(d, 10);
+            a = RL(a + F2(b,c,d) + X[ 0] + unchecked((int) 0x5a827999),  12) + e; c = RL(c, 10);
+            e = RL(e + F2(a,b,c) + X[ 9] + unchecked((int) 0x5a827999),  15) + d; b = RL(b, 10);
+            d = RL(d + F2(e,a,b) + X[ 5] + unchecked((int) 0x5a827999),   9) + c; a = RL(a, 10);
+            c = RL(c + F2(d,e,a) + X[ 2] + unchecked((int) 0x5a827999),  11) + b; e = RL(e, 10);
+            b = RL(b + F2(c,d,e) + X[14] + unchecked((int) 0x5a827999),   7) + a; d = RL(d, 10);
+            a = RL(a + F2(b,c,d) + X[11] + unchecked((int) 0x5a827999),  13) + e; c = RL(c, 10);
+            e = RL(e + F2(a,b,c) + X[ 8] + unchecked((int) 0x5a827999),  12) + d; b = RL(b, 10);
+
+            // right
+            ee = RL(ee + F4(aa,bb,cc) + X[ 6] + unchecked((int) 0x5c4dd124),   9) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F4(ee,aa,bb) + X[11] + unchecked((int) 0x5c4dd124),  13) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F4(dd,ee,aa) + X[ 3] + unchecked((int) 0x5c4dd124),  15) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F4(cc,dd,ee) + X[ 7] + unchecked((int) 0x5c4dd124),   7) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F4(bb,cc,dd) + X[ 0] + unchecked((int) 0x5c4dd124),  12) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F4(aa,bb,cc) + X[13] + unchecked((int) 0x5c4dd124),   8) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F4(ee,aa,bb) + X[ 5] + unchecked((int) 0x5c4dd124),   9) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F4(dd,ee,aa) + X[10] + unchecked((int) 0x5c4dd124),  11) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F4(cc,dd,ee) + X[14] + unchecked((int) 0x5c4dd124),   7) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F4(bb,cc,dd) + X[15] + unchecked((int) 0x5c4dd124),   7) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F4(aa,bb,cc) + X[ 8] + unchecked((int) 0x5c4dd124),  12) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F4(ee,aa,bb) + X[12] + unchecked((int) 0x5c4dd124),   7) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F4(dd,ee,aa) + X[ 4] + unchecked((int) 0x5c4dd124),   6) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F4(cc,dd,ee) + X[ 9] + unchecked((int) 0x5c4dd124),  15) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F4(bb,cc,dd) + X[ 1] + unchecked((int) 0x5c4dd124),  13) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F4(aa,bb,cc) + X[ 2] + unchecked((int) 0x5c4dd124),  11) + dd; bb = RL(bb, 10);
+
+            //
+            // Rounds 32-47
+            //
+            // left
+            d = RL(d + F3(e,a,b) + X[ 3] + unchecked((int) 0x6ed9eba1),  11) + c; a = RL(a, 10);
+            c = RL(c + F3(d,e,a) + X[10] + unchecked((int) 0x6ed9eba1),  13) + b; e = RL(e, 10);
+            b = RL(b + F3(c,d,e) + X[14] + unchecked((int) 0x6ed9eba1),   6) + a; d = RL(d, 10);
+            a = RL(a + F3(b,c,d) + X[ 4] + unchecked((int) 0x6ed9eba1),   7) + e; c = RL(c, 10);
+            e = RL(e + F3(a,b,c) + X[ 9] + unchecked((int) 0x6ed9eba1),  14) + d; b = RL(b, 10);
+            d = RL(d + F3(e,a,b) + X[15] + unchecked((int) 0x6ed9eba1),   9) + c; a = RL(a, 10);
+            c = RL(c + F3(d,e,a) + X[ 8] + unchecked((int) 0x6ed9eba1),  13) + b; e = RL(e, 10);
+            b = RL(b + F3(c,d,e) + X[ 1] + unchecked((int) 0x6ed9eba1),  15) + a; d = RL(d, 10);
+            a = RL(a + F3(b,c,d) + X[ 2] + unchecked((int) 0x6ed9eba1),  14) + e; c = RL(c, 10);
+            e = RL(e + F3(a,b,c) + X[ 7] + unchecked((int) 0x6ed9eba1),   8) + d; b = RL(b, 10);
+            d = RL(d + F3(e,a,b) + X[ 0] + unchecked((int) 0x6ed9eba1),  13) + c; a = RL(a, 10);
+            c = RL(c + F3(d,e,a) + X[ 6] + unchecked((int) 0x6ed9eba1),   6) + b; e = RL(e, 10);
+            b = RL(b + F3(c,d,e) + X[13] + unchecked((int) 0x6ed9eba1),   5) + a; d = RL(d, 10);
+            a = RL(a + F3(b,c,d) + X[11] + unchecked((int) 0x6ed9eba1),  12) + e; c = RL(c, 10);
+            e = RL(e + F3(a,b,c) + X[ 5] + unchecked((int) 0x6ed9eba1),   7) + d; b = RL(b, 10);
+            d = RL(d + F3(e,a,b) + X[12] + unchecked((int) 0x6ed9eba1),   5) + c; a = RL(a, 10);
+
+            // right
+            dd = RL(dd + F3(ee,aa,bb) + X[15] + unchecked((int) 0x6d703ef3),   9) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F3(dd,ee,aa) + X[ 5] + unchecked((int) 0x6d703ef3),   7) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F3(cc,dd,ee) + X[ 1] + unchecked((int) 0x6d703ef3),  15) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F3(bb,cc,dd) + X[ 3] + unchecked((int) 0x6d703ef3),  11) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F3(aa,bb,cc) + X[ 7] + unchecked((int) 0x6d703ef3),   8) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F3(ee,aa,bb) + X[14] + unchecked((int) 0x6d703ef3),   6) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F3(dd,ee,aa) + X[ 6] + unchecked((int) 0x6d703ef3),   6) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F3(cc,dd,ee) + X[ 9] + unchecked((int) 0x6d703ef3),  14) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F3(bb,cc,dd) + X[11] + unchecked((int) 0x6d703ef3),  12) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F3(aa,bb,cc) + X[ 8] + unchecked((int) 0x6d703ef3),  13) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F3(ee,aa,bb) + X[12] + unchecked((int) 0x6d703ef3),   5) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F3(dd,ee,aa) + X[ 2] + unchecked((int) 0x6d703ef3),  14) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F3(cc,dd,ee) + X[10] + unchecked((int) 0x6d703ef3),  13) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F3(bb,cc,dd) + X[ 0] + unchecked((int) 0x6d703ef3),  13) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F3(aa,bb,cc) + X[ 4] + unchecked((int) 0x6d703ef3),   7) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F3(ee,aa,bb) + X[13] + unchecked((int) 0x6d703ef3),   5) + cc; aa = RL(aa, 10);
+
+            //
+            // Rounds 48-63
+            //
+            // left
+            c = RL(c + F4(d,e,a) + X[ 1] + unchecked((int) 0x8f1bbcdc),  11) + b; e = RL(e, 10);
+            b = RL(b + F4(c,d,e) + X[ 9] + unchecked((int) 0x8f1bbcdc),  12) + a; d = RL(d, 10);
+            a = RL(a + F4(b,c,d) + X[11] + unchecked((int) 0x8f1bbcdc), 14) + e; c = RL(c, 10);
+            e = RL(e + F4(a,b,c) + X[10] + unchecked((int) 0x8f1bbcdc), 15) + d; b = RL(b, 10);
+            d = RL(d + F4(e,a,b) + X[ 0] + unchecked((int) 0x8f1bbcdc), 14) + c; a = RL(a, 10);
+            c = RL(c + F4(d,e,a) + X[ 8] + unchecked((int) 0x8f1bbcdc), 15) + b; e = RL(e, 10);
+            b = RL(b + F4(c,d,e) + X[12] + unchecked((int) 0x8f1bbcdc),  9) + a; d = RL(d, 10);
+            a = RL(a + F4(b,c,d) + X[ 4] + unchecked((int) 0x8f1bbcdc),  8) + e; c = RL(c, 10);
+            e = RL(e + F4(a,b,c) + X[13] + unchecked((int) 0x8f1bbcdc),  9) + d; b = RL(b, 10);
+            d = RL(d + F4(e,a,b) + X[ 3] + unchecked((int) 0x8f1bbcdc), 14) + c; a = RL(a, 10);
+            c = RL(c + F4(d,e,a) + X[ 7] + unchecked((int) 0x8f1bbcdc),  5) + b; e = RL(e, 10);
+            b = RL(b + F4(c,d,e) + X[15] + unchecked((int) 0x8f1bbcdc),  6) + a; d = RL(d, 10);
+            a = RL(a + F4(b,c,d) + X[14] + unchecked((int) 0x8f1bbcdc),  8) + e; c = RL(c, 10);
+            e = RL(e + F4(a,b,c) + X[ 5] + unchecked((int) 0x8f1bbcdc),  6) + d; b = RL(b, 10);
+            d = RL(d + F4(e,a,b) + X[ 6] + unchecked((int) 0x8f1bbcdc),  5) + c; a = RL(a, 10);
+            c = RL(c + F4(d,e,a) + X[ 2] + unchecked((int) 0x8f1bbcdc), 12) + b; e = RL(e, 10);
+
+            // right
+            cc = RL(cc + F2(dd,ee,aa) + X[ 8] + unchecked((int) 0x7a6d76e9),  15) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F2(cc,dd,ee) + X[ 6] + unchecked((int) 0x7a6d76e9),   5) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F2(bb,cc,dd) + X[ 4] + unchecked((int) 0x7a6d76e9),   8) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F2(aa,bb,cc) + X[ 1] + unchecked((int) 0x7a6d76e9),  11) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F2(ee,aa,bb) + X[ 3] + unchecked((int) 0x7a6d76e9),  14) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F2(dd,ee,aa) + X[11] + unchecked((int) 0x7a6d76e9),  14) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F2(cc,dd,ee) + X[15] + unchecked((int) 0x7a6d76e9),   6) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F2(bb,cc,dd) + X[ 0] + unchecked((int) 0x7a6d76e9),  14) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F2(aa,bb,cc) + X[ 5] + unchecked((int) 0x7a6d76e9),   6) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F2(ee,aa,bb) + X[12] + unchecked((int) 0x7a6d76e9),   9) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F2(dd,ee,aa) + X[ 2] + unchecked((int) 0x7a6d76e9),  12) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F2(cc,dd,ee) + X[13] + unchecked((int) 0x7a6d76e9),   9) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F2(bb,cc,dd) + X[ 9] + unchecked((int) 0x7a6d76e9),  12) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F2(aa,bb,cc) + X[ 7] + unchecked((int) 0x7a6d76e9),   5) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F2(ee,aa,bb) + X[10] + unchecked((int) 0x7a6d76e9),  15) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F2(dd,ee,aa) + X[14] + unchecked((int) 0x7a6d76e9),   8) + bb; ee = RL(ee, 10);
+
+            //
+            // Rounds 64-79
+            //
+            // left
+            b = RL(b + F5(c,d,e) + X[ 4] + unchecked((int) 0xa953fd4e),  9) + a; d = RL(d, 10);
+            a = RL(a + F5(b,c,d) + X[ 0] + unchecked((int) 0xa953fd4e), 15) + e; c = RL(c, 10);
+            e = RL(e + F5(a,b,c) + X[ 5] + unchecked((int) 0xa953fd4e),  5) + d; b = RL(b, 10);
+            d = RL(d + F5(e,a,b) + X[ 9] + unchecked((int) 0xa953fd4e), 11) + c; a = RL(a, 10);
+            c = RL(c + F5(d,e,a) + X[ 7] + unchecked((int) 0xa953fd4e),  6) + b; e = RL(e, 10);
+            b = RL(b + F5(c,d,e) + X[12] + unchecked((int) 0xa953fd4e),  8) + a; d = RL(d, 10);
+            a = RL(a + F5(b,c,d) + X[ 2] + unchecked((int) 0xa953fd4e), 13) + e; c = RL(c, 10);
+            e = RL(e + F5(a,b,c) + X[10] + unchecked((int) 0xa953fd4e), 12) + d; b = RL(b, 10);
+            d = RL(d + F5(e,a,b) + X[14] + unchecked((int) 0xa953fd4e),  5) + c; a = RL(a, 10);
+            c = RL(c + F5(d,e,a) + X[ 1] + unchecked((int) 0xa953fd4e), 12) + b; e = RL(e, 10);
+            b = RL(b + F5(c,d,e) + X[ 3] + unchecked((int) 0xa953fd4e), 13) + a; d = RL(d, 10);
+            a = RL(a + F5(b,c,d) + X[ 8] + unchecked((int) 0xa953fd4e), 14) + e; c = RL(c, 10);
+            e = RL(e + F5(a,b,c) + X[11] + unchecked((int) 0xa953fd4e), 11) + d; b = RL(b, 10);
+            d = RL(d + F5(e,a,b) + X[ 6] + unchecked((int) 0xa953fd4e),  8) + c; a = RL(a, 10);
+            c = RL(c + F5(d,e,a) + X[15] + unchecked((int) 0xa953fd4e),  5) + b; e = RL(e, 10);
+            b = RL(b + F5(c,d,e) + X[13] + unchecked((int) 0xa953fd4e),  6) + a; d = RL(d, 10);
+
+            // right
+            bb = RL(bb + F1(cc,dd,ee) + X[12],  8) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F1(bb,cc,dd) + X[15],  5) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F1(aa,bb,cc) + X[10], 12) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F1(ee,aa,bb) + X[ 4],  9) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F1(dd,ee,aa) + X[ 1], 12) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F1(cc,dd,ee) + X[ 5],  5) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F1(bb,cc,dd) + X[ 8], 14) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F1(aa,bb,cc) + X[ 7],  6) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F1(ee,aa,bb) + X[ 6],  8) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F1(dd,ee,aa) + X[ 2], 13) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F1(cc,dd,ee) + X[13],  6) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F1(bb,cc,dd) + X[14],  5) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F1(aa,bb,cc) + X[ 0], 15) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F1(ee,aa,bb) + X[ 3], 13) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F1(dd,ee,aa) + X[ 9], 11) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F1(cc,dd,ee) + X[11], 11) + aa; dd = RL(dd, 10);
+
+            dd += c + H1;
+            H1 = H2 + d + ee;
+            H2 = H3 + e + aa;
+            H3 = H4 + a + bb;
+            H4 = H0 + b + cc;
+            H0 = dd;
+
+            //
+            // reset the offset and clean out the word buffer.
+            //
+            xOff = 0;
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+        }
+    }
+
+}
diff --git a/Crypto/src/crypto/digests/RipeMD256Digest.cs b/Crypto/src/crypto/digests/RipeMD256Digest.cs
new file mode 100644
index 000000000..950e94f80
--- /dev/null
+++ b/Crypto/src/crypto/digests/RipeMD256Digest.cs
@@ -0,0 +1,409 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /// <remarks>
+    /// <p>Implementation of RipeMD256.</p>
+    /// <p><b>Note:</b> this algorithm offers the same level of security as RipeMD128.</p>
+    /// </remarks>
+    public class RipeMD256Digest
+		: GeneralDigest
+    {
+        public override string AlgorithmName
+		{
+			get { return "RIPEMD256"; }
+		}
+
+		public override int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		private const int DigestLength = 32;
+
+		private int H0, H1, H2, H3, H4, H5, H6, H7; // IV's
+
+		private int[] X = new int[16];
+        private int xOff;
+
+        /// <summary> Standard constructor</summary>
+        public RipeMD256Digest()
+        {
+            Reset();
+        }
+
+        /// <summary> Copy constructor.  This will copy the state of the provided
+        /// message digest.
+        /// </summary>
+        public RipeMD256Digest(RipeMD256Digest t):base(t)
+        {
+
+            H0 = t.H0;
+            H1 = t.H1;
+            H2 = t.H2;
+            H3 = t.H3;
+            H4 = t.H4;
+            H5 = t.H5;
+            H6 = t.H6;
+            H7 = t.H7;
+
+            Array.Copy(t.X, 0, X, 0, t.X.Length);
+            xOff = t.xOff;
+        }
+
+        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);
+
+            if (xOff == 16)
+            {
+                ProcessBlock();
+            }
+        }
+
+        internal override void ProcessLength(
+            long bitLength)
+        {
+            if (xOff > 14)
+            {
+                ProcessBlock();
+            }
+
+            X[14] = (int)(bitLength & 0xffffffff);
+            X[15] = (int)((ulong)bitLength >> 32);
+        }
+
+        private void UnpackWord(
+            int word,
+            byte[] outBytes,
+            int outOff)
+        {
+            outBytes[outOff] = (byte)(uint)word;
+            outBytes[outOff + 1] = (byte)((uint)word >> 8);
+            outBytes[outOff + 2] = (byte)((uint)word >> 16);
+            outBytes[outOff + 3] = (byte)((uint)word >> 24);
+        }
+
+        public override int DoFinal(byte[] output, int outOff)
+        {
+            Finish();
+
+            UnpackWord(H0, output, outOff);
+            UnpackWord(H1, output, outOff + 4);
+            UnpackWord(H2, output, outOff + 8);
+            UnpackWord(H3, output, outOff + 12);
+            UnpackWord(H4, output, outOff + 16);
+            UnpackWord(H5, output, outOff + 20);
+            UnpackWord(H6, output, outOff + 24);
+            UnpackWord(H7, output, outOff + 28);
+
+            Reset();
+
+            return DigestLength;
+        }
+
+        /// <summary> reset the chaining variables to the IV values.</summary>
+        public override void  Reset()
+        {
+            base.Reset();
+
+            H0 = unchecked((int)0x67452301);
+            H1 = unchecked((int)0xefcdab89);
+            H2 = unchecked((int)0x98badcfe);
+            H3 = unchecked((int)0x10325476);
+            H4 = unchecked((int)0x76543210);
+            H5 = unchecked((int)0xFEDCBA98);
+            H6 = unchecked((int)0x89ABCDEF);
+            H7 = unchecked((int)0x01234567);
+
+            xOff = 0;
+
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+        }
+
+        /*
+        * rotate int x left n bits.
+        */
+        private int RL(
+            int x,
+            int n)
+        {
+            return (x << n) | (int)((uint)x >> (32 - n));
+        }
+
+        /*
+        * f1,f2,f3,f4 are the basic RipeMD128 functions.
+        */
+
+        /*
+        * F
+        */
+        private int F1(int x, int y, int z)
+        {
+            return x ^ y ^ z;
+        }
+
+        /*
+        * G
+        */
+        private int F2(int x, int y, int z)
+        {
+            return (x & y) | (~ x & z);
+        }
+
+        /*
+        * H
+        */
+        private int F3(int x, int y, int z)
+        {
+            return (x | ~ y) ^ z;
+        }
+
+        /*
+        * I
+        */
+        private int F4(int x, int y, int z)
+        {
+            return (x & z) | (y & ~ z);
+        }
+
+        private int F1(int a, int b, int c, int d, int x, int s)
+        {
+            return RL(a + F1(b, c, d) + x, s);
+        }
+
+        private int F2(int a, int b, int c, int d, int x, int s)
+        {
+            return RL(a + F2(b, c, d) + x + unchecked((int)0x5a827999), s);
+        }
+
+        private int F3(int a, int b, int c, int d, int x, int s)
+        {
+            return RL(a + F3(b, c, d) + x + unchecked((int)0x6ed9eba1), s);
+        }
+
+        private int F4(int a, int b, int c, int d, int x, int s)
+        {
+            return RL(a + F4(b, c, d) + x + unchecked((int)0x8f1bbcdc), s);
+        }
+
+        private int FF1(int a, int b, int c, int d, int x, int s)
+        {
+            return RL(a + F1(b, c, d) + x, s);
+        }
+
+        private int FF2(int a, int b, int c, int d, int x, int s)
+        {
+            return RL(a + F2(b, c, d) + x + unchecked((int)0x6d703ef3), s);
+        }
+
+        private int FF3(int a, int b, int c, int d, int x, int s)
+        {
+            return RL(a + F3(b, c, d) + x + unchecked((int)0x5c4dd124), s);
+        }
+
+        private int FF4(int a, int b, int c, int d, int x, int s)
+        {
+            return RL(a + F4(b, c, d) + x + unchecked((int)0x50a28be6), s);
+        }
+
+        internal override void ProcessBlock()
+        {
+            int a, aa;
+            int b, bb;
+            int c, cc;
+            int d, dd;
+            int t;
+
+            a = H0;
+            b = H1;
+            c = H2;
+            d = H3;
+            aa = H4;
+            bb = H5;
+            cc = H6;
+            dd = H7;
+
+            //
+            // Round 1
+            //
+
+            a = F1(a, b, c, d, X[0], 11);
+            d = F1(d, a, b, c, X[1], 14);
+            c = F1(c, d, a, b, X[2], 15);
+            b = F1(b, c, d, a, X[3], 12);
+            a = F1(a, b, c, d, X[4], 5);
+            d = F1(d, a, b, c, X[5], 8);
+            c = F1(c, d, a, b, X[6], 7);
+            b = F1(b, c, d, a, X[7], 9);
+            a = F1(a, b, c, d, X[8], 11);
+            d = F1(d, a, b, c, X[9], 13);
+            c = F1(c, d, a, b, X[10], 14);
+            b = F1(b, c, d, a, X[11], 15);
+            a = F1(a, b, c, d, X[12], 6);
+            d = F1(d, a, b, c, X[13], 7);
+            c = F1(c, d, a, b, X[14], 9);
+            b = F1(b, c, d, a, X[15], 8);
+
+            aa = FF4(aa, bb, cc, dd, X[5], 8);
+            dd = FF4(dd, aa, bb, cc, X[14], 9);
+            cc = FF4(cc, dd, aa, bb, X[7], 9);
+            bb = FF4(bb, cc, dd, aa, X[0], 11);
+            aa = FF4(aa, bb, cc, dd, X[9], 13);
+            dd = FF4(dd, aa, bb, cc, X[2], 15);
+            cc = FF4(cc, dd, aa, bb, X[11], 15);
+            bb = FF4(bb, cc, dd, aa, X[4], 5);
+            aa = FF4(aa, bb, cc, dd, X[13], 7);
+            dd = FF4(dd, aa, bb, cc, X[6], 7);
+            cc = FF4(cc, dd, aa, bb, X[15], 8);
+            bb = FF4(bb, cc, dd, aa, X[8], 11);
+            aa = FF4(aa, bb, cc, dd, X[1], 14);
+            dd = FF4(dd, aa, bb, cc, X[10], 14);
+            cc = FF4(cc, dd, aa, bb, X[3], 12);
+            bb = FF4(bb, cc, dd, aa, X[12], 6);
+
+            t = a; a = aa; aa = t;
+
+            //
+            // Round 2
+            //
+            a = F2(a, b, c, d, X[7], 7);
+            d = F2(d, a, b, c, X[4], 6);
+            c = F2(c, d, a, b, X[13], 8);
+            b = F2(b, c, d, a, X[1], 13);
+            a = F2(a, b, c, d, X[10], 11);
+            d = F2(d, a, b, c, X[6], 9);
+            c = F2(c, d, a, b, X[15], 7);
+            b = F2(b, c, d, a, X[3], 15);
+            a = F2(a, b, c, d, X[12], 7);
+            d = F2(d, a, b, c, X[0], 12);
+            c = F2(c, d, a, b, X[9], 15);
+            b = F2(b, c, d, a, X[5], 9);
+            a = F2(a, b, c, d, X[2], 11);
+            d = F2(d, a, b, c, X[14], 7);
+            c = F2(c, d, a, b, X[11], 13);
+            b = F2(b, c, d, a, X[8], 12);
+
+            aa = FF3(aa, bb, cc, dd, X[6], 9);
+            dd = FF3(dd, aa, bb, cc, X[11], 13);
+            cc = FF3(cc, dd, aa, bb, X[3], 15);
+            bb = FF3(bb, cc, dd, aa, X[7], 7);
+            aa = FF3(aa, bb, cc, dd, X[0], 12);
+            dd = FF3(dd, aa, bb, cc, X[13], 8);
+            cc = FF3(cc, dd, aa, bb, X[5], 9);
+            bb = FF3(bb, cc, dd, aa, X[10], 11);
+            aa = FF3(aa, bb, cc, dd, X[14], 7);
+            dd = FF3(dd, aa, bb, cc, X[15], 7);
+            cc = FF3(cc, dd, aa, bb, X[8], 12);
+            bb = FF3(bb, cc, dd, aa, X[12], 7);
+            aa = FF3(aa, bb, cc, dd, X[4], 6);
+            dd = FF3(dd, aa, bb, cc, X[9], 15);
+            cc = FF3(cc, dd, aa, bb, X[1], 13);
+            bb = FF3(bb, cc, dd, aa, X[2], 11);
+
+            t = b; b = bb; bb = t;
+
+            //
+            // Round 3
+            //
+            a = F3(a, b, c, d, X[3], 11);
+            d = F3(d, a, b, c, X[10], 13);
+            c = F3(c, d, a, b, X[14], 6);
+            b = F3(b, c, d, a, X[4], 7);
+            a = F3(a, b, c, d, X[9], 14);
+            d = F3(d, a, b, c, X[15], 9);
+            c = F3(c, d, a, b, X[8], 13);
+            b = F3(b, c, d, a, X[1], 15);
+            a = F3(a, b, c, d, X[2], 14);
+            d = F3(d, a, b, c, X[7], 8);
+            c = F3(c, d, a, b, X[0], 13);
+            b = F3(b, c, d, a, X[6], 6);
+            a = F3(a, b, c, d, X[13], 5);
+            d = F3(d, a, b, c, X[11], 12);
+            c = F3(c, d, a, b, X[5], 7);
+            b = F3(b, c, d, a, X[12], 5);
+
+            aa = FF2(aa, bb, cc, dd, X[15], 9);
+            dd = FF2(dd, aa, bb, cc, X[5], 7);
+            cc = FF2(cc, dd, aa, bb, X[1], 15);
+            bb = FF2(bb, cc, dd, aa, X[3], 11);
+            aa = FF2(aa, bb, cc, dd, X[7], 8);
+            dd = FF2(dd, aa, bb, cc, X[14], 6);
+            cc = FF2(cc, dd, aa, bb, X[6], 6);
+            bb = FF2(bb, cc, dd, aa, X[9], 14);
+            aa = FF2(aa, bb, cc, dd, X[11], 12);
+            dd = FF2(dd, aa, bb, cc, X[8], 13);
+            cc = FF2(cc, dd, aa, bb, X[12], 5);
+            bb = FF2(bb, cc, dd, aa, X[2], 14);
+            aa = FF2(aa, bb, cc, dd, X[10], 13);
+            dd = FF2(dd, aa, bb, cc, X[0], 13);
+            cc = FF2(cc, dd, aa, bb, X[4], 7);
+            bb = FF2(bb, cc, dd, aa, X[13], 5);
+
+            t = c; c = cc; cc = t;
+
+            //
+            // Round 4
+            //
+            a = F4(a, b, c, d, X[1], 11);
+            d = F4(d, a, b, c, X[9], 12);
+            c = F4(c, d, a, b, X[11], 14);
+            b = F4(b, c, d, a, X[10], 15);
+            a = F4(a, b, c, d, X[0], 14);
+            d = F4(d, a, b, c, X[8], 15);
+            c = F4(c, d, a, b, X[12], 9);
+            b = F4(b, c, d, a, X[4], 8);
+            a = F4(a, b, c, d, X[13], 9);
+            d = F4(d, a, b, c, X[3], 14);
+            c = F4(c, d, a, b, X[7], 5);
+            b = F4(b, c, d, a, X[15], 6);
+            a = F4(a, b, c, d, X[14], 8);
+            d = F4(d, a, b, c, X[5], 6);
+            c = F4(c, d, a, b, X[6], 5);
+            b = F4(b, c, d, a, X[2], 12);
+
+            aa = FF1(aa, bb, cc, dd, X[8], 15);
+            dd = FF1(dd, aa, bb, cc, X[6], 5);
+            cc = FF1(cc, dd, aa, bb, X[4], 8);
+            bb = FF1(bb, cc, dd, aa, X[1], 11);
+            aa = FF1(aa, bb, cc, dd, X[3], 14);
+            dd = FF1(dd, aa, bb, cc, X[11], 14);
+            cc = FF1(cc, dd, aa, bb, X[15], 6);
+            bb = FF1(bb, cc, dd, aa, X[0], 14);
+            aa = FF1(aa, bb, cc, dd, X[5], 6);
+            dd = FF1(dd, aa, bb, cc, X[12], 9);
+            cc = FF1(cc, dd, aa, bb, X[2], 12);
+            bb = FF1(bb, cc, dd, aa, X[13], 9);
+            aa = FF1(aa, bb, cc, dd, X[9], 12);
+            dd = FF1(dd, aa, bb, cc, X[7], 5);
+            cc = FF1(cc, dd, aa, bb, X[10], 15);
+            bb = FF1(bb, cc, dd, aa, X[14], 8);
+
+            t = d; d = dd; dd = t;
+
+            H0 += a;
+            H1 += b;
+            H2 += c;
+            H3 += d;
+            H4 += aa;
+            H5 += bb;
+            H6 += cc;
+            H7 += dd;
+
+            //
+            // reset the offset and clean out the word buffer.
+            //
+            xOff = 0;
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+        }
+    }
+}
diff --git a/Crypto/src/crypto/digests/RipeMD320Digest.cs b/Crypto/src/crypto/digests/RipeMD320Digest.cs
new file mode 100644
index 000000000..25c74baef
--- /dev/null
+++ b/Crypto/src/crypto/digests/RipeMD320Digest.cs
@@ -0,0 +1,438 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+	/// <remarks>
+	/// <p>Implementation of RipeMD 320.</p>
+	/// <p><b>Note:</b> this algorithm offers the same level of security as RipeMD160.</p>
+	/// </remarks>
+    public class RipeMD320Digest
+		: GeneralDigest
+    {
+        public override string AlgorithmName
+		{
+			get { return "RIPEMD320"; }
+		}
+
+		public override int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		private const int DigestLength = 40;
+
+		private int H0, H1, H2, H3, H4, H5, H6, H7, H8, H9; // IV's
+
+        private int[] X = new int[16];
+        private int xOff;
+
+        /// <summary> Standard constructor</summary>
+        public RipeMD320Digest()
+        {
+            Reset();
+        }
+
+        /// <summary> Copy constructor.  This will copy the state of the provided
+        /// message digest.
+        /// </summary>
+        public RipeMD320Digest(RipeMD320Digest t)
+			: base(t)
+        {
+
+            H0 = t.H0;
+            H1 = t.H1;
+            H2 = t.H2;
+            H3 = t.H3;
+            H4 = t.H4;
+            H5 = t.H5;
+            H6 = t.H6;
+            H7 = t.H7;
+            H8 = t.H8;
+            H9 = t.H9;
+
+            Array.Copy(t.X, 0, X, 0, t.X.Length);
+            xOff = t.xOff;
+        }
+
+        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);
+
+            if (xOff == 16)
+            {
+                ProcessBlock();
+            }
+        }
+
+        internal override void ProcessLength(
+            long bitLength)
+        {
+            if (xOff > 14)
+            {
+                ProcessBlock();
+            }
+
+            X[14] = (int)(bitLength & 0xffffffff);
+            X[15] = (int)((ulong)bitLength >> 32);
+        }
+
+        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);
+        }
+
+        public override int DoFinal(byte[] output, int outOff)
+        {
+            Finish();
+
+            UnpackWord(H0, output, outOff);
+            UnpackWord(H1, output, outOff + 4);
+            UnpackWord(H2, output, outOff + 8);
+            UnpackWord(H3, output, outOff + 12);
+            UnpackWord(H4, output, outOff + 16);
+            UnpackWord(H5, output, outOff + 20);
+            UnpackWord(H6, output, outOff + 24);
+            UnpackWord(H7, output, outOff + 28);
+            UnpackWord(H8, output, outOff + 32);
+            UnpackWord(H9, output, outOff + 36);
+
+            Reset();
+
+            return DigestLength;
+        }
+
+        /// <summary> reset the chaining variables to the IV values.</summary>
+        public override void  Reset()
+        {
+            base.Reset();
+
+            H0 = unchecked((int) 0x67452301);
+            H1 = unchecked((int) 0xefcdab89);
+            H2 = unchecked((int) 0x98badcfe);
+            H3 = unchecked((int) 0x10325476);
+            H4 = unchecked((int) 0xc3d2e1f0);
+            H5 = unchecked((int) 0x76543210);
+            H6 = unchecked((int) 0xFEDCBA98);
+            H7 = unchecked((int) 0x89ABCDEF);
+            H8 = unchecked((int) 0x01234567);
+            H9 = unchecked((int) 0x3C2D1E0F);
+
+            xOff = 0;
+
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+        }
+
+        /*
+        * rotate int x left n bits.
+        */
+        private int RL(
+            int x,
+            int n)
+        {
+            return (x << n) | (int)(((uint)x) >> (32 - n));
+        }
+
+        /*
+        * f1,f2,f3,f4,f5 are the basic RipeMD160 functions.
+        */
+
+        /*
+        * rounds 0-15
+        */
+        private int F1(int x, int y, int z)
+        {
+            return x ^ y ^ z;
+        }
+
+        /*
+        * rounds 16-31
+        */
+        private int F2(int x, int y, int z)
+        {
+            return (x & y) | (~ x & z);
+        }
+
+        /*
+        * rounds 32-47
+        */
+        private int F3(int x, int y, int z)
+        {
+            return (x | ~ y) ^ z;
+        }
+
+        /*
+        * rounds 48-63
+        */
+        private int F4(int x, int y, int z)
+        {
+            return (x & z) | (y & ~ z);
+        }
+
+        /*
+        * rounds 64-79
+        */
+        private int F5(int x, int y, int z)
+        {
+            return x ^ (y | ~z);
+        }
+
+        internal override void ProcessBlock()
+        {
+            int a, aa;
+            int b, bb;
+            int c, cc;
+            int d, dd;
+            int e, ee;
+            int t;
+
+            a = H0;
+            b = H1;
+            c = H2;
+            d = H3;
+            e = H4;
+            aa = H5;
+            bb = H6;
+            cc = H7;
+            dd = H8;
+            ee = H9;
+
+            //
+            // Rounds 1 - 16
+            //
+            // left
+            a = RL(a + F1(b, c, d) + X[0], 11) + e; c = RL(c, 10);
+            e = RL(e + F1(a, b, c) + X[1], 14) + d; b = RL(b, 10);
+            d = RL(d + F1(e, a, b) + X[2], 15) + c; a = RL(a, 10);
+            c = RL(c + F1(d, e, a) + X[3], 12) + b; e = RL(e, 10);
+            b = RL(b + F1(c, d, e) + X[4], 5) + a; d = RL(d, 10);
+            a = RL(a + F1(b, c, d) + X[5], 8) + e; c = RL(c, 10);
+            e = RL(e + F1(a, b, c) + X[6], 7) + d; b = RL(b, 10);
+            d = RL(d + F1(e, a, b) + X[7], 9) + c; a = RL(a, 10);
+            c = RL(c + F1(d, e, a) + X[8], 11) + b; e = RL(e, 10);
+            b = RL(b + F1(c, d, e) + X[9], 13) + a; d = RL(d, 10);
+            a = RL(a + F1(b, c, d) + X[10], 14) + e; c = RL(c, 10);
+            e = RL(e + F1(a, b, c) + X[11], 15) + d; b = RL(b, 10);
+            d = RL(d + F1(e, a, b) + X[12], 6) + c; a = RL(a, 10);
+            c = RL(c + F1(d, e, a) + X[13], 7) + b; e = RL(e, 10);
+            b = RL(b + F1(c, d, e) + X[14], 9) + a; d = RL(d, 10);
+            a = RL(a + F1(b, c, d) + X[15], 8) + e; c = RL(c, 10);
+
+            // right
+            aa = RL(aa + F5(bb, cc, dd) + X[5] + unchecked((int)0x50a28be6), 8) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F5(aa, bb, cc) + X[14] + unchecked((int)0x50a28be6), 9) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F5(ee, aa, bb) + X[7] + unchecked((int)0x50a28be6), 9) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F5(dd, ee, aa) + X[0] + unchecked((int)0x50a28be6), 11) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F5(cc, dd, ee) + X[9] + unchecked((int)0x50a28be6), 13) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F5(bb, cc, dd) + X[2] + unchecked((int)0x50a28be6), 15) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F5(aa, bb, cc) + X[11] + unchecked((int)0x50a28be6), 15) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F5(ee, aa, bb) + X[4] + unchecked((int)0x50a28be6), 5) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F5(dd, ee, aa) + X[13] + unchecked((int)0x50a28be6), 7) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F5(cc, dd, ee) + X[6] + unchecked((int)0x50a28be6), 7) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F5(bb, cc, dd) + X[15] + unchecked((int)0x50a28be6), 8) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F5(aa, bb, cc) + X[8] + unchecked((int)0x50a28be6), 11) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F5(ee, aa, bb) + X[1] + unchecked((int)0x50a28be6), 14) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F5(dd, ee, aa) + X[10] + unchecked((int)0x50a28be6), 14) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F5(cc, dd, ee) + X[3] + unchecked((int)0x50a28be6), 12) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F5(bb, cc, dd) + X[12] + unchecked((int)0x50a28be6), 6) + ee; cc = RL(cc, 10);
+
+            t = a; a = aa; aa = t;
+            //
+            // Rounds 16-31
+            //
+            // left
+            e = RL(e + F2(a, b, c) + X[7] + unchecked((int)0x5a827999), 7) + d; b = RL(b, 10);
+            d = RL(d + F2(e, a, b) + X[4] + unchecked((int)0x5a827999), 6) + c; a = RL(a, 10);
+            c = RL(c + F2(d, e, a) + X[13] + unchecked((int)0x5a827999), 8) + b; e = RL(e, 10);
+            b = RL(b + F2(c, d, e) + X[1] + unchecked((int)0x5a827999), 13) + a; d = RL(d, 10);
+            a = RL(a + F2(b, c, d) + X[10] + unchecked((int)0x5a827999), 11) + e; c = RL(c, 10);
+            e = RL(e + F2(a, b, c) + X[6] + unchecked((int)0x5a827999), 9) + d; b = RL(b, 10);
+            d = RL(d + F2(e, a, b) + X[15] + unchecked((int)0x5a827999), 7) + c; a = RL(a, 10);
+            c = RL(c + F2(d, e, a) + X[3] + unchecked((int)0x5a827999), 15) + b; e = RL(e, 10);
+            b = RL(b + F2(c, d, e) + X[12] + unchecked((int)0x5a827999), 7) + a; d = RL(d, 10);
+            a = RL(a + F2(b, c, d) + X[0] + unchecked((int)0x5a827999), 12) + e; c = RL(c, 10);
+            e = RL(e + F2(a, b, c) + X[9] + unchecked((int)0x5a827999), 15) + d; b = RL(b, 10);
+            d = RL(d + F2(e, a, b) + X[5] + unchecked((int)0x5a827999), 9) + c; a = RL(a, 10);
+            c = RL(c + F2(d, e, a) + X[2] + unchecked((int)0x5a827999), 11) + b; e = RL(e, 10);
+            b = RL(b + F2(c, d, e) + X[14] + unchecked((int)0x5a827999), 7) + a; d = RL(d, 10);
+            a = RL(a + F2(b, c, d) + X[11] + unchecked((int)0x5a827999), 13) + e; c = RL(c, 10);
+            e = RL(e + F2(a, b, c) + X[8] + unchecked((int)0x5a827999), 12) + d; b = RL(b, 10);
+
+            // right
+            ee = RL(ee + F4(aa, bb, cc) + X[6] + unchecked((int)0x5c4dd124), 9) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F4(ee, aa, bb) + X[11] + unchecked((int)0x5c4dd124), 13) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F4(dd, ee, aa) + X[3] + unchecked((int)0x5c4dd124), 15) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F4(cc, dd, ee) + X[7] + unchecked((int)0x5c4dd124), 7) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F4(bb, cc, dd) + X[0] + unchecked((int)0x5c4dd124), 12) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F4(aa, bb, cc) + X[13] + unchecked((int)0x5c4dd124), 8) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F4(ee, aa, bb) + X[5] + unchecked((int)0x5c4dd124), 9) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F4(dd, ee, aa) + X[10] + unchecked((int)0x5c4dd124), 11) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F4(cc, dd, ee) + X[14] + unchecked((int)0x5c4dd124), 7) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F4(bb, cc, dd) + X[15] + unchecked((int)0x5c4dd124), 7) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F4(aa, bb, cc) + X[8] + unchecked((int)0x5c4dd124), 12) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F4(ee, aa, bb) + X[12] + unchecked((int)0x5c4dd124), 7) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F4(dd, ee, aa) + X[4] + unchecked((int)0x5c4dd124), 6) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F4(cc, dd, ee) + X[9] + unchecked((int)0x5c4dd124), 15) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F4(bb, cc, dd) + X[1] + unchecked((int)0x5c4dd124), 13) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F4(aa, bb, cc) + X[2] + unchecked((int)0x5c4dd124), 11) + dd; bb = RL(bb, 10);
+
+            t = b; b = bb; bb = t;
+
+            //
+            // Rounds 32-47
+            //
+            // left
+            d = RL(d + F3(e, a, b) + X[3] + unchecked((int)0x6ed9eba1), 11) + c; a = RL(a, 10);
+            c = RL(c + F3(d, e, a) + X[10] + unchecked((int)0x6ed9eba1), 13) + b; e = RL(e, 10);
+            b = RL(b + F3(c, d, e) + X[14] + unchecked((int)0x6ed9eba1), 6) + a; d = RL(d, 10);
+            a = RL(a + F3(b, c, d) + X[4] + unchecked((int)0x6ed9eba1), 7) + e; c = RL(c, 10);
+            e = RL(e + F3(a, b, c) + X[9] + unchecked((int)0x6ed9eba1), 14) + d; b = RL(b, 10);
+            d = RL(d + F3(e, a, b) + X[15] + unchecked((int)0x6ed9eba1), 9) + c; a = RL(a, 10);
+            c = RL(c + F3(d, e, a) + X[8] + unchecked((int)0x6ed9eba1), 13) + b; e = RL(e, 10);
+            b = RL(b + F3(c, d, e) + X[1] + unchecked((int)0x6ed9eba1), 15) + a; d = RL(d, 10);
+            a = RL(a + F3(b, c, d) + X[2] + unchecked((int)0x6ed9eba1), 14) + e; c = RL(c, 10);
+            e = RL(e + F3(a, b, c) + X[7] + unchecked((int)0x6ed9eba1), 8) + d; b = RL(b, 10);
+            d = RL(d + F3(e, a, b) + X[0] + unchecked((int)0x6ed9eba1), 13) + c; a = RL(a, 10);
+            c = RL(c + F3(d, e, a) + X[6] + unchecked((int)0x6ed9eba1), 6) + b; e = RL(e, 10);
+            b = RL(b + F3(c, d, e) + X[13] + unchecked((int)0x6ed9eba1), 5) + a; d = RL(d, 10);
+            a = RL(a + F3(b, c, d) + X[11] + unchecked((int)0x6ed9eba1), 12) + e; c = RL(c, 10);
+            e = RL(e + F3(a, b, c) + X[5] + unchecked((int)0x6ed9eba1), 7) + d; b = RL(b, 10);
+            d = RL(d + F3(e, a, b) + X[12] + unchecked((int)0x6ed9eba1), 5) + c; a = RL(a, 10);
+
+            // right
+            dd = RL(dd + F3(ee, aa, bb) + X[15] + unchecked((int)0x6d703ef3), 9) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F3(dd, ee, aa) + X[5] + unchecked((int)0x6d703ef3), 7) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F3(cc, dd, ee) + X[1] + unchecked((int)0x6d703ef3), 15) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F3(bb, cc, dd) + X[3] + unchecked((int)0x6d703ef3), 11) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F3(aa, bb, cc) + X[7] + unchecked((int)0x6d703ef3), 8) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F3(ee, aa, bb) + X[14] + unchecked((int)0x6d703ef3), 6) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F3(dd, ee, aa) + X[6] + unchecked((int)0x6d703ef3), 6) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F3(cc, dd, ee) + X[9] + unchecked((int)0x6d703ef3), 14) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F3(bb, cc, dd) + X[11] + unchecked((int)0x6d703ef3), 12) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F3(aa, bb, cc) + X[8] + unchecked((int)0x6d703ef3), 13) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F3(ee, aa, bb) + X[12] + unchecked((int)0x6d703ef3), 5) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F3(dd, ee, aa) + X[2] + unchecked((int)0x6d703ef3), 14) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F3(cc, dd, ee) + X[10] + unchecked((int)0x6d703ef3), 13) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F3(bb, cc, dd) + X[0] + unchecked((int)0x6d703ef3), 13) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F3(aa, bb, cc) + X[4] + unchecked((int)0x6d703ef3), 7) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F3(ee, aa, bb) + X[13] + unchecked((int)0x6d703ef3), 5) + cc; aa = RL(aa, 10);
+
+            t = c; c = cc; cc = t;
+
+            //
+            // Rounds 48-63
+            //
+            // left
+            c = RL(c + F4(d, e, a) + X[1] + unchecked((int)0x8f1bbcdc), 11) + b; e = RL(e, 10);
+            b = RL(b + F4(c, d, e) + X[9] + unchecked((int)0x8f1bbcdc), 12) + a; d = RL(d, 10);
+            a = RL(a + F4(b, c, d) + X[11] + unchecked((int)0x8f1bbcdc), 14) + e; c = RL(c, 10);
+            e = RL(e + F4(a, b, c) + X[10] + unchecked((int)0x8f1bbcdc), 15) + d; b = RL(b, 10);
+            d = RL(d + F4(e, a, b) + X[0] + unchecked((int)0x8f1bbcdc), 14) + c; a = RL(a, 10);
+            c = RL(c + F4(d, e, a) + X[8] + unchecked((int)0x8f1bbcdc), 15) + b; e = RL(e, 10);
+            b = RL(b + F4(c, d, e) + X[12] + unchecked((int)0x8f1bbcdc), 9) + a; d = RL(d, 10);
+            a = RL(a + F4(b, c, d) + X[4] + unchecked((int)0x8f1bbcdc), 8) + e; c = RL(c, 10);
+            e = RL(e + F4(a, b, c) + X[13] + unchecked((int)0x8f1bbcdc), 9) + d; b = RL(b, 10);
+            d = RL(d + F4(e, a, b) + X[3] + unchecked((int)0x8f1bbcdc), 14) + c; a = RL(a, 10);
+            c = RL(c + F4(d, e, a) + X[7] + unchecked((int)0x8f1bbcdc), 5) + b; e = RL(e, 10);
+            b = RL(b + F4(c, d, e) + X[15] + unchecked((int)0x8f1bbcdc), 6) + a; d = RL(d, 10);
+            a = RL(a + F4(b, c, d) + X[14] + unchecked((int)0x8f1bbcdc), 8) + e; c = RL(c, 10);
+            e = RL(e + F4(a, b, c) + X[5] + unchecked((int)0x8f1bbcdc), 6) + d; b = RL(b, 10);
+            d = RL(d + F4(e, a, b) + X[6] + unchecked((int)0x8f1bbcdc), 5) + c; a = RL(a, 10);
+            c = RL(c + F4(d, e, a) + X[2] + unchecked((int)0x8f1bbcdc), 12) + b; e = RL(e, 10);
+
+            // right
+            cc = RL(cc + F2(dd, ee, aa) + X[8] + unchecked((int)0x7a6d76e9), 15) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F2(cc, dd, ee) + X[6] + unchecked((int)0x7a6d76e9), 5) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F2(bb, cc, dd) + X[4] + unchecked((int)0x7a6d76e9), 8) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F2(aa, bb, cc) + X[1] + unchecked((int)0x7a6d76e9), 11) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F2(ee, aa, bb) + X[3] + unchecked((int)0x7a6d76e9), 14) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F2(dd, ee, aa) + X[11] + unchecked((int)0x7a6d76e9), 14) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F2(cc, dd, ee) + X[15] + unchecked((int)0x7a6d76e9), 6) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F2(bb, cc, dd) + X[0] + unchecked((int)0x7a6d76e9), 14) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F2(aa, bb, cc) + X[5] + unchecked((int)0x7a6d76e9), 6) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F2(ee, aa, bb) + X[12] + unchecked((int)0x7a6d76e9), 9) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F2(dd, ee, aa) + X[2] + unchecked((int)0x7a6d76e9), 12) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F2(cc, dd, ee) + X[13] + unchecked((int)0x7a6d76e9), 9) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F2(bb, cc, dd) + X[9] + unchecked((int)0x7a6d76e9), 12) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F2(aa, bb, cc) + X[7] + unchecked((int)0x7a6d76e9), 5) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F2(ee, aa, bb) + X[10] + unchecked((int)0x7a6d76e9), 15) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F2(dd, ee, aa) + X[14] + unchecked((int)0x7a6d76e9), 8) + bb; ee = RL(ee, 10);
+
+            t = d; d = dd; dd = t;
+
+            //
+            // Rounds 64-79
+            //
+            // left
+            b = RL(b + F5(c, d, e) + X[4] + unchecked((int)0xa953fd4e), 9) + a; d = RL(d, 10);
+            a = RL(a + F5(b, c, d) + X[0] + unchecked((int)0xa953fd4e), 15) + e; c = RL(c, 10);
+            e = RL(e + F5(a, b, c) + X[5] + unchecked((int)0xa953fd4e), 5) + d; b = RL(b, 10);
+            d = RL(d + F5(e, a, b) + X[9] + unchecked((int)0xa953fd4e), 11) + c; a = RL(a, 10);
+            c = RL(c + F5(d, e, a) + X[7] + unchecked((int)0xa953fd4e), 6) + b; e = RL(e, 10);
+            b = RL(b + F5(c, d, e) + X[12] + unchecked((int)0xa953fd4e), 8) + a; d = RL(d, 10);
+            a = RL(a + F5(b, c, d) + X[2] + unchecked((int)0xa953fd4e), 13) + e; c = RL(c, 10);
+            e = RL(e + F5(a, b, c) + X[10] + unchecked((int)0xa953fd4e), 12) + d; b = RL(b, 10);
+            d = RL(d + F5(e, a, b) + X[14] + unchecked((int)0xa953fd4e), 5) + c; a = RL(a, 10);
+            c = RL(c + F5(d, e, a) + X[1] + unchecked((int)0xa953fd4e), 12) + b; e = RL(e, 10);
+            b = RL(b + F5(c, d, e) + X[3] + unchecked((int)0xa953fd4e), 13) + a; d = RL(d, 10);
+            a = RL(a + F5(b, c, d) + X[8] + unchecked((int)0xa953fd4e), 14) + e; c = RL(c, 10);
+            e = RL(e + F5(a, b, c) + X[11] + unchecked((int)0xa953fd4e), 11) + d; b = RL(b, 10);
+            d = RL(d + F5(e, a, b) + X[6] + unchecked((int)0xa953fd4e), 8) + c; a = RL(a, 10);
+            c = RL(c + F5(d, e, a) + X[15] + unchecked((int)0xa953fd4e), 5) + b; e = RL(e, 10);
+            b = RL(b + F5(c, d, e) + X[13] + unchecked((int)0xa953fd4e), 6) + a; d = RL(d, 10);
+
+            // right
+            bb = RL(bb + F1(cc, dd, ee) + X[12], 8) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F1(bb, cc, dd) + X[15], 5) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F1(aa, bb, cc) + X[10], 12) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F1(ee, aa, bb) + X[4], 9) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F1(dd, ee, aa) + X[1], 12) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F1(cc, dd, ee) + X[5], 5) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F1(bb, cc, dd) + X[8], 14) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F1(aa, bb, cc) + X[7], 6) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F1(ee, aa, bb) + X[6], 8) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F1(dd, ee, aa) + X[2], 13) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F1(cc, dd, ee) + X[13], 6) + aa; dd = RL(dd, 10);
+            aa = RL(aa + F1(bb, cc, dd) + X[14], 5) + ee; cc = RL(cc, 10);
+            ee = RL(ee + F1(aa, bb, cc) + X[0], 15) + dd; bb = RL(bb, 10);
+            dd = RL(dd + F1(ee, aa, bb) + X[3], 13) + cc; aa = RL(aa, 10);
+            cc = RL(cc + F1(dd, ee, aa) + X[9], 11) + bb; ee = RL(ee, 10);
+            bb = RL(bb + F1(cc, dd, ee) + X[11], 11) + aa; dd = RL(dd, 10);
+
+            //
+            // do (e, ee) swap as part of assignment.
+            //
+
+            H0 += a;
+            H1 += b;
+            H2 += c;
+            H3 += d;
+            H4 += ee;
+            H5 += aa;
+            H6 += bb;
+            H7 += cc;
+            H8 += dd;
+            H9 += e;
+
+            //
+            // reset the offset and clean out the word buffer.
+            //
+            xOff = 0;
+            for (int i = 0; i != X.Length; i++)
+            {
+                X[i] = 0;
+            }
+        }
+    }
+}
diff --git a/Crypto/src/crypto/digests/Sha1Digest.cs b/Crypto/src/crypto/digests/Sha1Digest.cs
new file mode 100644
index 000000000..9d8c1a4cf
--- /dev/null
+++ b/Crypto/src/crypto/digests/Sha1Digest.cs
@@ -0,0 +1,263 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+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!
+     */
+    public class Sha1Digest
+		: GeneralDigest
+    {
+        private const int DigestLength = 20;
+
+        private uint H1, H2, H3, H4, H5;
+
+        private uint[] X = new uint[80];
+        private int xOff;
+
+		public Sha1Digest()
+        {
+            Reset();
+        }
+
+        /**
+         * Copy constructor.  This will copy the state of the provided
+         * message digest.
+         */
+        public Sha1Digest(Sha1Digest t)
+			: base(t)
+        {
+            H1 = t.H1;
+            H2 = t.H2;
+            H3 = t.H3;
+            H4 = t.H4;
+            H5 = t.H5;
+
+            Array.Copy(t.X, 0, X, 0, t.X.Length);
+            xOff = t.xOff;
+        }
+
+		public override string AlgorithmName
+		{
+			get { return "SHA-1"; }
+		}
+
+		public override int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		internal override void ProcessWord(
+            byte[]  input,
+            int     inOff)
+        {
+			X[xOff] = Pack.BE_To_UInt32(input, inOff);
+
+			if (++xOff == 16)
+			{
+				ProcessBlock();
+			}
+        }
+
+		internal override void ProcessLength(long    bitLength)
+        {
+			if (xOff > 14)
+			{
+				ProcessBlock();
+			}
+
+            X[14] = (uint)((ulong)bitLength >> 32);
+            X[15] = (uint)((ulong)bitLength);
+        }
+
+        public override int DoFinal(
+            byte[]  output,
+            int     outOff)
+        {
+            Finish();
+
+            Pack.UInt32_To_BE(H1, output, outOff);
+            Pack.UInt32_To_BE(H2, output, outOff + 4);
+            Pack.UInt32_To_BE(H3, output, outOff + 8);
+            Pack.UInt32_To_BE(H4, output, outOff + 12);
+            Pack.UInt32_To_BE(H5, output, outOff + 16);
+
+            Reset();
+
+            return DigestLength;
+        }
+
+        /**
+         * reset the chaining variables
+         */
+        public override void Reset()
+        {
+            base.Reset();
+
+            H1 = 0x67452301;
+            H2 = 0xefcdab89;
+            H3 = 0x98badcfe;
+            H4 = 0x10325476;
+            H5 = 0xc3d2e1f0;
+
+            xOff = 0;
+			Array.Clear(X, 0, X.Length);
+        }
+
+        //
+        // Additive constants
+        //
+        private const uint Y1 = 0x5a827999;
+        private const uint Y2 = 0x6ed9eba1;
+        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 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);
+		}
+
+		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;
+			}
+
+            //
+            // set up working variables.
+            //
+            uint A = H1;
+            uint B = H2;
+            uint C = H3;
+            uint D = H4;
+            uint E = H5;
+
+            //
+            // round 1
+            //
+			int idx = 0;
+
+			for (int j = 0; j < 4; j++)
+			{
+				// E = rotateLeft(A, 5) + F(B, C, D) + E + X[idx++] + Y1
+				// B = rotateLeft(B, 30)
+				E += (A << 5 | (A >> 27)) + F(B, C, D) + X[idx++] + Y1;
+				B = B << 30 | (B >> 2);
+
+				D += (E << 5 | (E >> 27)) + F(A, B, C) + X[idx++] + Y1;
+				A = A << 30 | (A >> 2);
+
+				C += (D << 5 | (D >> 27)) + F(E, A, B) + X[idx++] + Y1;
+				E = E << 30 | (E >> 2);
+
+				B += (C << 5 | (C >> 27)) + F(D, E, A) + X[idx++] + Y1;
+				D = D << 30 | (D >> 2);
+
+				A += (B << 5 | (B >> 27)) + F(C, D, E) + X[idx++] + Y1;
+				C = C << 30 | (C >> 2);
+			}
+
+			//
+            // round 2
+            //
+			for (int j = 0; j < 4; j++)
+			{
+				// E = rotateLeft(A, 5) + H(B, C, D) + E + X[idx++] + Y2
+				// B = rotateLeft(B, 30)
+				E += (A << 5 | (A >> 27)) + H(B, C, D) + X[idx++] + Y2;
+				B = B << 30 | (B >> 2);
+
+				D += (E << 5 | (E >> 27)) + H(A, B, C) + X[idx++] + Y2;
+				A = A << 30 | (A >> 2);
+
+				C += (D << 5 | (D >> 27)) + H(E, A, B) + X[idx++] + Y2;
+				E = E << 30 | (E >> 2);
+
+				B += (C << 5 | (C >> 27)) + H(D, E, A) + X[idx++] + Y2;
+				D = D << 30 | (D >> 2);
+
+				A += (B << 5 | (B >> 27)) + H(C, D, E) + X[idx++] + Y2;
+				C = C << 30 | (C >> 2);
+			}
+
+			//
+            // round 3
+            //
+			for (int j = 0; j < 4; j++)
+			{
+				// E = rotateLeft(A, 5) + G(B, C, D) + E + X[idx++] + Y3
+				// B = rotateLeft(B, 30)
+				E += (A << 5 | (A >> 27)) + G(B, C, D) + X[idx++] + Y3;
+				B = B << 30 | (B >> 2);
+
+				D += (E << 5 | (E >> 27)) + G(A, B, C) + X[idx++] + Y3;
+				A = A << 30 | (A >> 2);
+
+				C += (D << 5 | (D >> 27)) + G(E, A, B) + X[idx++] + Y3;
+				E = E << 30 | (E >> 2);
+
+				B += (C << 5 | (C >> 27)) + G(D, E, A) + X[idx++] + Y3;
+				D = D << 30 | (D >> 2);
+
+				A += (B << 5 | (B >> 27)) + G(C, D, E) + X[idx++] + Y3;
+				C = C << 30 | (C >> 2);
+			}
+
+			//
+            // round 4
+            //
+			for (int j = 0; j < 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);
+		}
+    }
+}
diff --git a/Crypto/src/crypto/digests/Sha224Digest.cs b/Crypto/src/crypto/digests/Sha224Digest.cs
new file mode 100644
index 000000000..66ecd4ecd
--- /dev/null
+++ b/Crypto/src/crypto/digests/Sha224Digest.cs
@@ -0,0 +1,268 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /**
+     * SHA-224 as described in RFC 3874
+     * <pre>
+     *         block  word  digest
+     * SHA-1   512    32    160
+     * SHA-224 512    32    224
+     * SHA-256 512    32    256
+     * SHA-384 1024   64    384
+     * SHA-512 1024   64    512
+     * </pre>
+     */
+    public class Sha224Digest
+        : GeneralDigest
+    {
+        private const int DigestLength = 28;
+
+		private uint H1, H2, H3, H4, H5, H6, H7, H8;
+
+		private uint[] X = new uint[64];
+        private int     xOff;
+
+		/**
+         * Standard constructor
+         */
+        public Sha224Digest()
+        {
+            Reset();
+        }
+
+		/**
+         * Copy constructor.  This will copy the state of the provided
+         * message digest.
+         */
+         public Sha224Digest(
+			 Sha224Digest t)
+			 : base(t)
+        {
+            H1 = t.H1;
+            H2 = t.H2;
+            H3 = t.H3;
+            H4 = t.H4;
+            H5 = t.H5;
+            H6 = t.H6;
+            H7 = t.H7;
+            H8 = t.H8;
+
+            Array.Copy(t.X, 0, X, 0, t.X.Length);
+            xOff = t.xOff;
+        }
+
+		public override string AlgorithmName
+		{
+			get { return "SHA-224"; }
+		}
+
+		public override int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		internal override void ProcessWord(
+            byte[]  input,
+            int     inOff)
+        {
+			X[xOff] = Pack.BE_To_UInt32(input, inOff);
+
+			if (++xOff == 16)
+            {
+                ProcessBlock();
+            }
+        }
+
+		internal override void ProcessLength(
+            long bitLength)
+        {
+            if (xOff > 14)
+            {
+                ProcessBlock();
+            }
+
+            X[14] = (uint)((ulong)bitLength >> 32);
+            X[15] = (uint)((ulong)bitLength);
+        }
+
+        public override int DoFinal(
+            byte[]	output,
+            int		outOff)
+        {
+            Finish();
+
+			Pack.UInt32_To_BE(H1, output, outOff);
+            Pack.UInt32_To_BE(H2, output, outOff + 4);
+            Pack.UInt32_To_BE(H3, output, outOff + 8);
+            Pack.UInt32_To_BE(H4, output, outOff + 12);
+            Pack.UInt32_To_BE(H5, output, outOff + 16);
+            Pack.UInt32_To_BE(H6, output, outOff + 20);
+            Pack.UInt32_To_BE(H7, output, outOff + 24);
+
+			Reset();
+
+			return DigestLength;
+        }
+
+		/**
+         * reset the chaining variables
+         */
+        public override void Reset()
+        {
+            base.Reset();
+
+            /* SHA-224 initial hash value
+             */
+            H1 = 0xc1059ed8;
+            H2 = 0x367cd507;
+            H3 = 0x3070dd17;
+            H4 = 0xf70e5939;
+            H5 = 0xffc00b31;
+            H6 = 0x68581511;
+            H7 = 0x64f98fa7;
+            H8 = 0xbefa4fa4;
+
+			xOff = 0;
+			Array.Clear(X, 0, X.Length);
+        }
+
+        internal override void ProcessBlock()
+        {
+            //
+            // expand 16 word block into 64 word blocks.
+            //
+            for (int ti = 16; ti <= 63; ti++)
+            {
+                X[ti] = Theta1(X[ti - 2]) + X[ti - 7] + Theta0(X[ti - 15]) + X[ti - 16];
+            }
+
+			//
+            // set up working variables.
+            //
+            uint a = H1;
+            uint b = H2;
+            uint c = H3;
+            uint d = H4;
+            uint e = H5;
+            uint f = H6;
+            uint g = H7;
+            uint h = H8;
+
+			int t = 0;
+			for(int i = 0; i < 8; i ++)
+			{
+				// t = 8 * i
+				h += Sum1(e) + Ch(e, f, g) + K[t] + X[t];
+				d += h;
+				h += Sum0(a) + Maj(a, b, c);
+				++t;
+
+				// t = 8 * i + 1
+				g += Sum1(d) + Ch(d, e, f) + K[t] + X[t];
+				c += g;
+				g += Sum0(h) + Maj(h, a, b);
+				++t;
+
+				// t = 8 * i + 2
+				f += Sum1(c) + Ch(c, d, e) + K[t] + X[t];
+				b += f;
+				f += Sum0(g) + Maj(g, h, a);
+				++t;
+
+				// t = 8 * i + 3
+				e += Sum1(b) + Ch(b, c, d) + K[t] + X[t];
+				a += e;
+				e += Sum0(f) + Maj(f, g, h);
+				++t;
+
+				// t = 8 * i + 4
+				d += Sum1(a) + Ch(a, b, c) + K[t] + X[t];
+				h += d;
+				d += Sum0(e) + Maj(e, f, g);
+				++t;
+
+				// t = 8 * i + 5
+				c += Sum1(h) + Ch(h, a, b) + K[t] + X[t];
+				g += c;
+				c += Sum0(d) + Maj(d, e, f);
+				++t;
+
+				// t = 8 * i + 6
+				b += Sum1(g) + Ch(g, h, a) + K[t] + X[t];
+				f += b;
+				b += Sum0(c) + Maj(c, d, e);
+				++t;
+
+				// t = 8 * i + 7
+				a += Sum1(f) + Ch(f, g, h) + K[t] + X[t];
+				e += a;
+				a += Sum0(b) + Maj(b, c, d);
+				++t;
+			}
+
+			H1 += a;
+            H2 += b;
+            H3 += c;
+            H4 += d;
+            H5 += e;
+            H6 += f;
+            H7 += g;
+            H8 += h;
+
+            //
+            // reset the offset and clean out the word buffer.
+            //
+            xOff = 0;
+			Array.Clear(X, 0, 16);
+		}
+
+		/* SHA-224 functions */
+        private static uint Ch(uint x, uint y, uint z)
+        {
+            return (x & y) ^ (~x & z);
+        }
+
+        private static uint Maj(uint x, uint y, uint z)
+        {
+            return (x & y) ^ (x & z) ^ (y & z);
+        }
+
+        private static uint Sum0(uint x)
+        {
+	        return ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10));
+        }
+
+        private static uint Sum1(uint x)
+        {
+			return ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7));
+        }
+
+		private static uint Theta0(uint x)
+        {
+	        return ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ (x >> 3);
+        }
+
+        private static uint Theta1(uint x)
+        {
+	        return ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10);
+        }
+
+		/* SHA-224 Constants
+         * (represent the first 32 bits of the fractional parts of the
+         * cube roots of the first sixty-four prime numbers)
+         */
+        internal static readonly uint[] K = {
+            0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+            0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+            0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+            0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+            0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+            0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+			0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+            0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+        };
+    }
+}
diff --git a/Crypto/src/crypto/digests/Sha256Digest.cs b/Crypto/src/crypto/digests/Sha256Digest.cs
new file mode 100644
index 000000000..1c00ab71f
--- /dev/null
+++ b/Crypto/src/crypto/digests/Sha256Digest.cs
@@ -0,0 +1,309 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /**
+    * Draft FIPS 180-2 implementation of SHA-256. <b>Note:</b> As this is
+    * based on a draft this implementation is subject to change.
+    *
+    * <pre>
+    *         block  word  digest
+    * SHA-1   512    32    160
+    * SHA-256 512    32    256
+    * SHA-384 1024   64    384
+    * SHA-512 1024   64    512
+    * </pre>
+    */
+    public class Sha256Digest
+		: GeneralDigest
+    {
+        private const int DigestLength = 32;
+
+        private uint H1, H2, H3, H4, H5, H6, H7, H8;
+        private uint[] X = new uint[64];
+        private int xOff;
+
+        public Sha256Digest()
+        {
+			initHs();
+        }
+
+        /**
+        * Copy constructor.  This will copy the state of the provided
+        * message digest.
+        */
+        public Sha256Digest(Sha256Digest t) : base(t)
+        {
+            H1 = t.H1;
+            H2 = t.H2;
+            H3 = t.H3;
+            H4 = t.H4;
+            H5 = t.H5;
+            H6 = t.H6;
+            H7 = t.H7;
+            H8 = t.H8;
+
+            Array.Copy(t.X, 0, X, 0, t.X.Length);
+            xOff = t.xOff;
+        }
+
+        public override string AlgorithmName
+		{
+			get { return "SHA-256"; }
+		}
+
+		public override int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		internal override void ProcessWord(
+            byte[]  input,
+            int     inOff)
+		{
+			X[xOff] = Pack.BE_To_UInt32(input, inOff);
+
+			if (++xOff == 16)
+            {
+                ProcessBlock();
+            }
+        }
+
+		internal override void ProcessLength(
+            long bitLength)
+        {
+            if (xOff > 14)
+            {
+                ProcessBlock();
+            }
+
+            X[14] = (uint)((ulong)bitLength >> 32);
+            X[15] = (uint)((ulong)bitLength);
+        }
+
+        public override int DoFinal(
+            byte[]  output,
+            int     outOff)
+        {
+            Finish();
+
+            Pack.UInt32_To_BE((uint)H1, output, outOff);
+            Pack.UInt32_To_BE((uint)H2, output, outOff + 4);
+            Pack.UInt32_To_BE((uint)H3, output, outOff + 8);
+            Pack.UInt32_To_BE((uint)H4, output, outOff + 12);
+            Pack.UInt32_To_BE((uint)H5, output, outOff + 16);
+            Pack.UInt32_To_BE((uint)H6, output, outOff + 20);
+            Pack.UInt32_To_BE((uint)H7, output, outOff + 24);
+            Pack.UInt32_To_BE((uint)H8, output, outOff + 28);
+
+            Reset();
+
+            return DigestLength;
+        }
+
+        /**
+        * reset the chaining variables
+        */
+        public override void Reset()
+        {
+            base.Reset();
+
+			initHs();
+
+            xOff = 0;
+			Array.Clear(X, 0, X.Length);
+        }
+
+		private void initHs()
+		{
+            /* SHA-256 initial hash value
+            * The first 32 bits of the fractional parts of the square roots
+            * of the first eight prime numbers
+            */
+            H1 = 0x6a09e667;
+            H2 = 0xbb67ae85;
+            H3 = 0x3c6ef372;
+            H4 = 0xa54ff53a;
+            H5 = 0x510e527f;
+            H6 = 0x9b05688c;
+            H7 = 0x1f83d9ab;
+            H8 = 0x5be0cd19;
+		}
+
+        internal override void ProcessBlock()
+        {
+            //
+            // expand 16 word block into 64 word blocks.
+            //
+            for (int ti = 16; ti <= 63; ti++)
+            {
+                X[ti] = Theta1(X[ti - 2]) + X[ti - 7] + Theta0(X[ti - 15]) + X[ti - 16];
+            }
+
+            //
+            // set up working variables.
+            //
+            uint a = H1;
+            uint b = H2;
+            uint c = H3;
+            uint d = H4;
+            uint e = H5;
+            uint f = H6;
+            uint g = H7;
+            uint h = H8;
+
+			int t = 0;
+			for(int i = 0; i < 8; ++i)
+			{
+				// t = 8 * i
+				h += Sum1Ch(e, f, g) + K[t] + X[t];
+				d += h;
+				h += Sum0Maj(a, b, c);
+				++t;
+
+				// t = 8 * i + 1
+				g += Sum1Ch(d, e, f) + K[t] + X[t];
+				c += g;
+				g += Sum0Maj(h, a, b);
+				++t;
+
+				// t = 8 * i + 2
+				f += Sum1Ch(c, d, e) + K[t] + X[t];
+				b += f;
+				f += Sum0Maj(g, h, a);
+				++t;
+
+				// t = 8 * i + 3
+				e += Sum1Ch(b, c, d) + K[t] + X[t];
+				a += e;
+				e += Sum0Maj(f, g, h);
+				++t;
+
+				// t = 8 * i + 4
+				d += Sum1Ch(a, b, c) + K[t] + X[t];
+				h += d;
+				d += Sum0Maj(e, f, g);
+				++t;
+
+				// t = 8 * i + 5
+				c += Sum1Ch(h, a, b) + K[t] + X[t];
+				g += c;
+				c += Sum0Maj(d, e, f);
+				++t;
+
+				// t = 8 * i + 6
+				b += Sum1Ch(g, h, a) + K[t] + X[t];
+				f += b;
+				b += Sum0Maj(c, d, e);
+				++t;
+
+				// t = 8 * i + 7
+				a += Sum1Ch(f, g, h) + K[t] + X[t];
+				e += a;
+				a += Sum0Maj(b, c, d);
+				++t;
+			}
+
+			H1 += a;
+            H2 += b;
+            H3 += c;
+            H4 += d;
+            H5 += e;
+            H6 += f;
+            H7 += g;
+            H8 += h;
+
+            //
+            // reset the offset and clean out the word buffer.
+            //
+            xOff = 0;
+			Array.Clear(X, 0, 16);
+        }
+
+		private static uint Sum1Ch(
+            uint    x,
+            uint    y,
+            uint    z)
+		{
+//			return Sum1(x) + Ch(x, y, z);
+	        return (((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7)))
+				+ ((x & y) ^ ((~x) & z));
+		}
+
+		private static uint Sum0Maj(
+            uint	x,
+            uint    y,
+            uint    z)
+		{
+//			return Sum0(x) + Maj(x, y, z);
+	        return (((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10)))
+				+ ((x & y) ^ (x & z) ^ (y & z));
+		}
+
+//		/* SHA-256 functions */
+//        private static uint Ch(
+//            uint    x,
+//            uint    y,
+//            uint    z)
+//        {
+//            return ((x & y) ^ ((~x) & z));
+//        }
+//
+//        private static uint Maj(
+//            uint	x,
+//            uint    y,
+//            uint    z)
+//        {
+//            return ((x & y) ^ (x & z) ^ (y & z));
+//        }
+//
+//        private static uint Sum0(
+//            uint x)
+//        {
+//	        return ((x >> 2) | (x << 30)) ^ ((x >> 13) | (x << 19)) ^ ((x >> 22) | (x << 10));
+//        }
+//
+//        private static uint Sum1(
+//            uint x)
+//        {
+//	        return ((x >> 6) | (x << 26)) ^ ((x >> 11) | (x << 21)) ^ ((x >> 25) | (x << 7));
+//        }
+
+        private static uint Theta0(
+            uint x)
+        {
+	        return ((x >> 7) | (x << 25)) ^ ((x >> 18) | (x << 14)) ^ (x >> 3);
+        }
+
+        private static uint Theta1(
+            uint x)
+        {
+	        return ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10);
+        }
+
+        /* SHA-256 Constants
+        * (represent the first 32 bits of the fractional parts of the
+        * cube roots of the first sixty-four prime numbers)
+        */
+        private static readonly uint[] K = {
+            0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+			0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+            0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+            0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+            0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+            0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+            0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+            0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+            0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+            0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+            0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+            0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+            0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+            0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+            0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+            0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+        };
+    }
+}
diff --git a/Crypto/src/crypto/digests/Sha384Digest.cs b/Crypto/src/crypto/digests/Sha384Digest.cs
new file mode 100644
index 000000000..f1372d0a9
--- /dev/null
+++ b/Crypto/src/crypto/digests/Sha384Digest.cs
@@ -0,0 +1,87 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /**
+     * Draft FIPS 180-2 implementation of SHA-384. <b>Note:</b> As this is
+     * based on a draft this implementation is subject to change.
+     *
+     * <pre>
+     *         block  word  digest
+     * SHA-1   512    32    160
+     * SHA-256 512    32    256
+     * SHA-384 1024   64    384
+     * SHA-512 1024   64    512
+     * </pre>
+     */
+    public class Sha384Digest
+		: LongDigest
+    {
+        private const int DigestLength = 48;
+
+		public Sha384Digest()
+        {
+        }
+
+        /**
+         * Copy constructor.  This will copy the state of the provided
+         * message digest.
+         */
+        public Sha384Digest(
+			Sha384Digest t)
+			: base(t)
+		{
+		}
+
+		public override string AlgorithmName
+		{
+			get { return "SHA-384"; }
+		}
+
+		public override int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		public override int DoFinal(
+            byte[]  output,
+            int     outOff)
+        {
+            Finish();
+
+            Pack.UInt64_To_BE(H1, output, outOff);
+            Pack.UInt64_To_BE(H2, output, outOff + 8);
+            Pack.UInt64_To_BE(H3, output, outOff + 16);
+            Pack.UInt64_To_BE(H4, output, outOff + 24);
+            Pack.UInt64_To_BE(H5, output, outOff + 32);
+            Pack.UInt64_To_BE(H6, output, outOff + 40);
+
+            Reset();
+
+            return DigestLength;
+        }
+
+        /**
+        * reset the chaining variables
+        */
+        public override void Reset()
+        {
+            base.Reset();
+
+            /* SHA-384 initial hash value
+                * The first 64 bits of the fractional parts of the square roots
+                * of the 9th through 16th prime numbers
+                */
+            H1 = 0xcbbb9d5dc1059ed8;
+            H2 = 0x629a292a367cd507;
+            H3 = 0x9159015a3070dd17;
+            H4 = 0x152fecd8f70e5939;
+            H5 = 0x67332667ffc00b31;
+            H6 = 0x8eb44a8768581511;
+            H7 = 0xdb0c2e0d64f98fa7;
+            H8 = 0x47b5481dbefa4fa4;
+        }
+    }
+}
diff --git a/Crypto/src/crypto/digests/Sha512Digest.cs b/Crypto/src/crypto/digests/Sha512Digest.cs
new file mode 100644
index 000000000..ed1a50819
--- /dev/null
+++ b/Crypto/src/crypto/digests/Sha512Digest.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /**
+     * Draft FIPS 180-2 implementation of SHA-512. <b>Note:</b> As this is
+     * based on a draft this implementation is subject to change.
+     *
+     * <pre>
+     *         block  word  digest
+     * SHA-1   512    32    160
+     * SHA-256 512    32    256
+     * SHA-384 1024   64    384
+     * SHA-512 1024   64    512
+     * </pre>
+     */
+    public class Sha512Digest
+		: LongDigest
+    {
+        private const int DigestLength = 64;
+
+		public Sha512Digest()
+        {
+        }
+
+		/**
+         * Copy constructor.  This will copy the state of the provided
+         * message digest.
+         */
+        public Sha512Digest(
+			Sha512Digest t)
+			: base(t)
+		{
+		}
+
+		public override string AlgorithmName
+		{
+			get { return "SHA-512"; }
+		}
+
+		public override int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		public override int DoFinal(
+            byte[]  output,
+            int     outOff)
+        {
+            Finish();
+
+            Pack.UInt64_To_BE(H1, output, outOff);
+            Pack.UInt64_To_BE(H2, output, outOff + 8);
+            Pack.UInt64_To_BE(H3, output, outOff + 16);
+            Pack.UInt64_To_BE(H4, output, outOff + 24);
+            Pack.UInt64_To_BE(H5, output, outOff + 32);
+            Pack.UInt64_To_BE(H6, output, outOff + 40);
+            Pack.UInt64_To_BE(H7, output, outOff + 48);
+            Pack.UInt64_To_BE(H8, output, outOff + 56);
+
+            Reset();
+
+            return DigestLength;
+
+        }
+
+        /**
+        * reset the chaining variables
+        */
+        public override void Reset()
+        {
+            base.Reset();
+
+            /* SHA-512 initial hash value
+             * The first 64 bits of the fractional parts of the square roots
+             * of the first eight prime numbers
+             */
+            H1 = 0x6a09e667f3bcc908;
+            H2 = 0xbb67ae8584caa73b;
+            H3 = 0x3c6ef372fe94f82b;
+            H4 = 0xa54ff53a5f1d36f1;
+            H5 = 0x510e527fade682d1;
+            H6 = 0x9b05688c2b3e6c1f;
+            H7 = 0x1f83d9abfb41bd6b;
+            H8 = 0x5be0cd19137e2179;
+        }
+    }
+}
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/TigerDigest.cs b/Crypto/src/crypto/digests/TigerDigest.cs
new file mode 100644
index 000000000..b8c9a7664
--- /dev/null
+++ b/Crypto/src/crypto/digests/TigerDigest.cs
@@ -0,0 +1,868 @@
+using System;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /**
+    * implementation of Tiger based on:
+    * <a href="http://www.cs.technion.ac.il/~biham/Reports/Tiger">
+    *  http://www.cs.technion.ac.il/~biham/Reports/Tiger</a>
+    */
+    public class TigerDigest
+		: IDigest
+    {
+        private const int MyByteLength = 64;
+
+        /*
+        * S-Boxes.
+        */
+        private static readonly long[] t1 = {
+            unchecked((long) 0x02AAB17CF7E90C5EL)   /*    0 */,    unchecked((long) 0xAC424B03E243A8ECL)   /*    1 */,
+            unchecked((long) 0x72CD5BE30DD5FCD3L)   /*    2 */,    unchecked((long) 0x6D019B93F6F97F3AL)   /*    3 */,
+            unchecked((long) 0xCD9978FFD21F9193L)   /*    4 */,    unchecked((long) 0x7573A1C9708029E2L)   /*    5 */,
+            unchecked((long) 0xB164326B922A83C3L)   /*    6 */,    unchecked((long) 0x46883EEE04915870L)   /*    7 */,
+            unchecked((long) 0xEAACE3057103ECE6L)   /*    8 */,    unchecked((long) 0xC54169B808A3535CL)   /*    9 */,
+            unchecked((long) 0x4CE754918DDEC47CL)   /*   10 */,    unchecked((long) 0x0AA2F4DFDC0DF40CL)   /*   11 */,
+            unchecked((long) 0x10B76F18A74DBEFAL)   /*   12 */,    unchecked((long) 0xC6CCB6235AD1AB6AL)   /*   13 */,
+            unchecked((long) 0x13726121572FE2FFL)   /*   14 */,    unchecked((long) 0x1A488C6F199D921EL)   /*   15 */,
+            unchecked((long) 0x4BC9F9F4DA0007CAL)   /*   16 */,    unchecked((long) 0x26F5E6F6E85241C7L)   /*   17 */,
+            unchecked((long) 0x859079DBEA5947B6L)   /*   18 */,    unchecked((long) 0x4F1885C5C99E8C92L)   /*   19 */,
+            unchecked((long) 0xD78E761EA96F864BL)   /*   20 */,    unchecked((long) 0x8E36428C52B5C17DL)   /*   21 */,
+            unchecked((long) 0x69CF6827373063C1L)   /*   22 */,    unchecked((long) 0xB607C93D9BB4C56EL)   /*   23 */,
+            unchecked((long) 0x7D820E760E76B5EAL)   /*   24 */,    unchecked((long) 0x645C9CC6F07FDC42L)   /*   25 */,
+            unchecked((long) 0xBF38A078243342E0L)   /*   26 */,    unchecked((long) 0x5F6B343C9D2E7D04L)   /*   27 */,
+            unchecked((long) 0xF2C28AEB600B0EC6L)   /*   28 */,    unchecked((long) 0x6C0ED85F7254BCACL)   /*   29 */,
+            unchecked((long) 0x71592281A4DB4FE5L)   /*   30 */,    unchecked((long) 0x1967FA69CE0FED9FL)   /*   31 */,
+            unchecked((long) 0xFD5293F8B96545DBL)   /*   32 */,    unchecked((long) 0xC879E9D7F2A7600BL)   /*   33 */,
+            unchecked((long) 0x860248920193194EL)   /*   34 */,    unchecked((long) 0xA4F9533B2D9CC0B3L)   /*   35 */,
+            unchecked((long) 0x9053836C15957613L)   /*   36 */,    unchecked((long) 0xDB6DCF8AFC357BF1L)   /*   37 */,
+            unchecked((long) 0x18BEEA7A7A370F57L)   /*   38 */,    unchecked((long) 0x037117CA50B99066L)   /*   39 */,
+            unchecked((long) 0x6AB30A9774424A35L)   /*   40 */,    unchecked((long) 0xF4E92F02E325249BL)   /*   41 */,
+            unchecked((long) 0x7739DB07061CCAE1L)   /*   42 */,    unchecked((long) 0xD8F3B49CECA42A05L)   /*   43 */,
+            unchecked((long) 0xBD56BE3F51382F73L)   /*   44 */,    unchecked((long) 0x45FAED5843B0BB28L)   /*   45 */,
+            unchecked((long) 0x1C813D5C11BF1F83L)   /*   46 */,    unchecked((long) 0x8AF0E4B6D75FA169L)   /*   47 */,
+            unchecked((long) 0x33EE18A487AD9999L)   /*   48 */,    unchecked((long) 0x3C26E8EAB1C94410L)   /*   49 */,
+            unchecked((long) 0xB510102BC0A822F9L)   /*   50 */,    unchecked((long) 0x141EEF310CE6123BL)   /*   51 */,
+            unchecked((long) 0xFC65B90059DDB154L)   /*   52 */,    unchecked((long) 0xE0158640C5E0E607L)   /*   53 */,
+            unchecked((long) 0x884E079826C3A3CFL)   /*   54 */,    unchecked((long) 0x930D0D9523C535FDL)   /*   55 */,
+            unchecked((long) 0x35638D754E9A2B00L)   /*   56 */,    unchecked((long) 0x4085FCCF40469DD5L)   /*   57 */,
+            unchecked((long) 0xC4B17AD28BE23A4CL)   /*   58 */,    unchecked((long) 0xCAB2F0FC6A3E6A2EL)   /*   59 */,
+            unchecked((long) 0x2860971A6B943FCDL)   /*   60 */,    unchecked((long) 0x3DDE6EE212E30446L)   /*   61 */,
+            unchecked((long) 0x6222F32AE01765AEL)   /*   62 */,    unchecked((long) 0x5D550BB5478308FEL)   /*   63 */,
+            unchecked((long) 0xA9EFA98DA0EDA22AL)   /*   64 */,    unchecked((long) 0xC351A71686C40DA7L)   /*   65 */,
+            unchecked((long) 0x1105586D9C867C84L)   /*   66 */,    unchecked((long) 0xDCFFEE85FDA22853L)   /*   67 */,
+            unchecked((long) 0xCCFBD0262C5EEF76L)   /*   68 */,    unchecked((long) 0xBAF294CB8990D201L)   /*   69 */,
+            unchecked((long) 0xE69464F52AFAD975L)   /*   70 */,    unchecked((long) 0x94B013AFDF133E14L)   /*   71 */,
+            unchecked((long) 0x06A7D1A32823C958L)   /*   72 */,    unchecked((long) 0x6F95FE5130F61119L)   /*   73 */,
+            unchecked((long) 0xD92AB34E462C06C0L)   /*   74 */,    unchecked((long) 0xED7BDE33887C71D2L)   /*   75 */,
+            unchecked((long) 0x79746D6E6518393EL)   /*   76 */,    unchecked((long) 0x5BA419385D713329L)   /*   77 */,
+            unchecked((long) 0x7C1BA6B948A97564L)   /*   78 */,    unchecked((long) 0x31987C197BFDAC67L)   /*   79 */,
+            unchecked((long) 0xDE6C23C44B053D02L)   /*   80 */,    unchecked((long) 0x581C49FED002D64DL)   /*   81 */,
+            unchecked((long) 0xDD474D6338261571L)   /*   82 */,    unchecked((long) 0xAA4546C3E473D062L)   /*   83 */,
+            unchecked((long) 0x928FCE349455F860L)   /*   84 */,    unchecked((long) 0x48161BBACAAB94D9L)   /*   85 */,
+            unchecked((long) 0x63912430770E6F68L)   /*   86 */,    unchecked((long) 0x6EC8A5E602C6641CL)   /*   87 */,
+            unchecked((long) 0x87282515337DDD2BL)   /*   88 */,    unchecked((long) 0x2CDA6B42034B701BL)   /*   89 */,
+            unchecked((long) 0xB03D37C181CB096DL)   /*   90 */,    unchecked((long) 0xE108438266C71C6FL)   /*   91 */,
+            unchecked((long) 0x2B3180C7EB51B255L)   /*   92 */,    unchecked((long) 0xDF92B82F96C08BBCL)   /*   93 */,
+            unchecked((long) 0x5C68C8C0A632F3BAL)   /*   94 */,    unchecked((long) 0x5504CC861C3D0556L)   /*   95 */,
+            unchecked((long) 0xABBFA4E55FB26B8FL)   /*   96 */,    unchecked((long) 0x41848B0AB3BACEB4L)   /*   97 */,
+            unchecked((long) 0xB334A273AA445D32L)   /*   98 */,    unchecked((long) 0xBCA696F0A85AD881L)   /*   99 */,
+            unchecked((long) 0x24F6EC65B528D56CL)   /*  100 */,    unchecked((long) 0x0CE1512E90F4524AL)   /*  101 */,
+            unchecked((long) 0x4E9DD79D5506D35AL)   /*  102 */,    unchecked((long) 0x258905FAC6CE9779L)   /*  103 */,
+            unchecked((long) 0x2019295B3E109B33L)   /*  104 */,    unchecked((long) 0xF8A9478B73A054CCL)   /*  105 */,
+            unchecked((long) 0x2924F2F934417EB0L)   /*  106 */,    unchecked((long) 0x3993357D536D1BC4L)   /*  107 */,
+            unchecked((long) 0x38A81AC21DB6FF8BL)   /*  108 */,    unchecked((long) 0x47C4FBF17D6016BFL)   /*  109 */,
+            unchecked((long) 0x1E0FAADD7667E3F5L)   /*  110 */,    unchecked((long) 0x7ABCFF62938BEB96L)   /*  111 */,
+            unchecked((long) 0xA78DAD948FC179C9L)   /*  112 */,    unchecked((long) 0x8F1F98B72911E50DL)   /*  113 */,
+            unchecked((long) 0x61E48EAE27121A91L)   /*  114 */,    unchecked((long) 0x4D62F7AD31859808L)   /*  115 */,
+            unchecked((long) 0xECEBA345EF5CEAEBL)   /*  116 */,    unchecked((long) 0xF5CEB25EBC9684CEL)   /*  117 */,
+            unchecked((long) 0xF633E20CB7F76221L)   /*  118 */,    unchecked((long) 0xA32CDF06AB8293E4L)   /*  119 */,
+            unchecked((long) 0x985A202CA5EE2CA4L)   /*  120 */,    unchecked((long) 0xCF0B8447CC8A8FB1L)   /*  121 */,
+            unchecked((long) 0x9F765244979859A3L)   /*  122 */,    unchecked((long) 0xA8D516B1A1240017L)   /*  123 */,
+            unchecked((long) 0x0BD7BA3EBB5DC726L)   /*  124 */,    unchecked((long) 0xE54BCA55B86ADB39L)   /*  125 */,
+            unchecked((long) 0x1D7A3AFD6C478063L)   /*  126 */,    unchecked((long) 0x519EC608E7669EDDL)   /*  127 */,
+            unchecked((long) 0x0E5715A2D149AA23L)   /*  128 */,    unchecked((long) 0x177D4571848FF194L)   /*  129 */,
+            unchecked((long) 0xEEB55F3241014C22L)   /*  130 */,    unchecked((long) 0x0F5E5CA13A6E2EC2L)   /*  131 */,
+            unchecked((long) 0x8029927B75F5C361L)   /*  132 */,    unchecked((long) 0xAD139FABC3D6E436L)   /*  133 */,
+            unchecked((long) 0x0D5DF1A94CCF402FL)   /*  134 */,    unchecked((long) 0x3E8BD948BEA5DFC8L)   /*  135 */,
+            unchecked((long) 0xA5A0D357BD3FF77EL)   /*  136 */,    unchecked((long) 0xA2D12E251F74F645L)   /*  137 */,
+            unchecked((long) 0x66FD9E525E81A082L)   /*  138 */,    unchecked((long) 0x2E0C90CE7F687A49L)   /*  139 */,
+            unchecked((long) 0xC2E8BCBEBA973BC5L)   /*  140 */,    unchecked((long) 0x000001BCE509745FL)   /*  141 */,
+            unchecked((long) 0x423777BBE6DAB3D6L)   /*  142 */,    unchecked((long) 0xD1661C7EAEF06EB5L)   /*  143 */,
+            unchecked((long) 0xA1781F354DAACFD8L)   /*  144 */,    unchecked((long) 0x2D11284A2B16AFFCL)   /*  145 */,
+            unchecked((long) 0xF1FC4F67FA891D1FL)   /*  146 */,    unchecked((long) 0x73ECC25DCB920ADAL)   /*  147 */,
+            unchecked((long) 0xAE610C22C2A12651L)   /*  148 */,    unchecked((long) 0x96E0A810D356B78AL)   /*  149 */,
+            unchecked((long) 0x5A9A381F2FE7870FL)   /*  150 */,    unchecked((long) 0xD5AD62EDE94E5530L)   /*  151 */,
+            unchecked((long) 0xD225E5E8368D1427L)   /*  152 */,    unchecked((long) 0x65977B70C7AF4631L)   /*  153 */,
+            unchecked((long) 0x99F889B2DE39D74FL)   /*  154 */,    unchecked((long) 0x233F30BF54E1D143L)   /*  155 */,
+            unchecked((long) 0x9A9675D3D9A63C97L)   /*  156 */,    unchecked((long) 0x5470554FF334F9A8L)   /*  157 */,
+            unchecked((long) 0x166ACB744A4F5688L)   /*  158 */,    unchecked((long) 0x70C74CAAB2E4AEADL)   /*  159 */,
+            unchecked((long) 0xF0D091646F294D12L)   /*  160 */,    unchecked((long) 0x57B82A89684031D1L)   /*  161 */,
+            unchecked((long) 0xEFD95A5A61BE0B6BL)   /*  162 */,    unchecked((long) 0x2FBD12E969F2F29AL)   /*  163 */,
+            unchecked((long) 0x9BD37013FEFF9FE8L)   /*  164 */,    unchecked((long) 0x3F9B0404D6085A06L)   /*  165 */,
+            unchecked((long) 0x4940C1F3166CFE15L)   /*  166 */,    unchecked((long) 0x09542C4DCDF3DEFBL)   /*  167 */,
+            unchecked((long) 0xB4C5218385CD5CE3L)   /*  168 */,    unchecked((long) 0xC935B7DC4462A641L)   /*  169 */,
+            unchecked((long) 0x3417F8A68ED3B63FL)   /*  170 */,    unchecked((long) 0xB80959295B215B40L)   /*  171 */,
+            unchecked((long) 0xF99CDAEF3B8C8572L)   /*  172 */,    unchecked((long) 0x018C0614F8FCB95DL)   /*  173 */,
+            unchecked((long) 0x1B14ACCD1A3ACDF3L)   /*  174 */,    unchecked((long) 0x84D471F200BB732DL)   /*  175 */,
+            unchecked((long) 0xC1A3110E95E8DA16L)   /*  176 */,    unchecked((long) 0x430A7220BF1A82B8L)   /*  177 */,
+            unchecked((long) 0xB77E090D39DF210EL)   /*  178 */,    unchecked((long) 0x5EF4BD9F3CD05E9DL)   /*  179 */,
+            unchecked((long) 0x9D4FF6DA7E57A444L)   /*  180 */,    unchecked((long) 0xDA1D60E183D4A5F8L)   /*  181 */,
+            unchecked((long) 0xB287C38417998E47L)   /*  182 */,    unchecked((long) 0xFE3EDC121BB31886L)   /*  183 */,
+            unchecked((long) 0xC7FE3CCC980CCBEFL)   /*  184 */,    unchecked((long) 0xE46FB590189BFD03L)   /*  185 */,
+            unchecked((long) 0x3732FD469A4C57DCL)   /*  186 */,    unchecked((long) 0x7EF700A07CF1AD65L)   /*  187 */,
+            unchecked((long) 0x59C64468A31D8859L)   /*  188 */,    unchecked((long) 0x762FB0B4D45B61F6L)   /*  189 */,
+            unchecked((long) 0x155BAED099047718L)   /*  190 */,    unchecked((long) 0x68755E4C3D50BAA6L)   /*  191 */,
+            unchecked((long) 0xE9214E7F22D8B4DFL)   /*  192 */,    unchecked((long) 0x2ADDBF532EAC95F4L)   /*  193 */,
+            unchecked((long) 0x32AE3909B4BD0109L)   /*  194 */,    unchecked((long) 0x834DF537B08E3450L)   /*  195 */,
+            unchecked((long) 0xFA209DA84220728DL)   /*  196 */,    unchecked((long) 0x9E691D9B9EFE23F7L)   /*  197 */,
+            unchecked((long) 0x0446D288C4AE8D7FL)   /*  198 */,    unchecked((long) 0x7B4CC524E169785BL)   /*  199 */,
+            unchecked((long) 0x21D87F0135CA1385L)   /*  200 */,    unchecked((long) 0xCEBB400F137B8AA5L)   /*  201 */,
+            unchecked((long) 0x272E2B66580796BEL)   /*  202 */,    unchecked((long) 0x3612264125C2B0DEL)   /*  203 */,
+            unchecked((long) 0x057702BDAD1EFBB2L)   /*  204 */,    unchecked((long) 0xD4BABB8EACF84BE9L)   /*  205 */,
+            unchecked((long) 0x91583139641BC67BL)   /*  206 */,    unchecked((long) 0x8BDC2DE08036E024L)   /*  207 */,
+            unchecked((long) 0x603C8156F49F68EDL)   /*  208 */,    unchecked((long) 0xF7D236F7DBEF5111L)   /*  209 */,
+            unchecked((long) 0x9727C4598AD21E80L)   /*  210 */,    unchecked((long) 0xA08A0896670A5FD7L)   /*  211 */,
+            unchecked((long) 0xCB4A8F4309EBA9CBL)   /*  212 */,    unchecked((long) 0x81AF564B0F7036A1L)   /*  213 */,
+            unchecked((long) 0xC0B99AA778199ABDL)   /*  214 */,    unchecked((long) 0x959F1EC83FC8E952L)   /*  215 */,
+            unchecked((long) 0x8C505077794A81B9L)   /*  216 */,    unchecked((long) 0x3ACAAF8F056338F0L)   /*  217 */,
+            unchecked((long) 0x07B43F50627A6778L)   /*  218 */,    unchecked((long) 0x4A44AB49F5ECCC77L)   /*  219 */,
+            unchecked((long) 0x3BC3D6E4B679EE98L)   /*  220 */,    unchecked((long) 0x9CC0D4D1CF14108CL)   /*  221 */,
+            unchecked((long) 0x4406C00B206BC8A0L)   /*  222 */,    unchecked((long) 0x82A18854C8D72D89L)   /*  223 */,
+            unchecked((long) 0x67E366B35C3C432CL)   /*  224 */,    unchecked((long) 0xB923DD61102B37F2L)   /*  225 */,
+            unchecked((long) 0x56AB2779D884271DL)   /*  226 */,    unchecked((long) 0xBE83E1B0FF1525AFL)   /*  227 */,
+            unchecked((long) 0xFB7C65D4217E49A9L)   /*  228 */,    unchecked((long) 0x6BDBE0E76D48E7D4L)   /*  229 */,
+            unchecked((long) 0x08DF828745D9179EL)   /*  230 */,    unchecked((long) 0x22EA6A9ADD53BD34L)   /*  231 */,
+            unchecked((long) 0xE36E141C5622200AL)   /*  232 */,    unchecked((long) 0x7F805D1B8CB750EEL)   /*  233 */,
+            unchecked((long) 0xAFE5C7A59F58E837L)   /*  234 */,    unchecked((long) 0xE27F996A4FB1C23CL)   /*  235 */,
+            unchecked((long) 0xD3867DFB0775F0D0L)   /*  236 */,    unchecked((long) 0xD0E673DE6E88891AL)   /*  237 */,
+            unchecked((long) 0x123AEB9EAFB86C25L)   /*  238 */,    unchecked((long) 0x30F1D5D5C145B895L)   /*  239 */,
+            unchecked((long) 0xBB434A2DEE7269E7L)   /*  240 */,    unchecked((long) 0x78CB67ECF931FA38L)   /*  241 */,
+            unchecked((long) 0xF33B0372323BBF9CL)   /*  242 */,    unchecked((long) 0x52D66336FB279C74L)   /*  243 */,
+            unchecked((long) 0x505F33AC0AFB4EAAL)   /*  244 */,    unchecked((long) 0xE8A5CD99A2CCE187L)   /*  245 */,
+            unchecked((long) 0x534974801E2D30BBL)   /*  246 */,    unchecked((long) 0x8D2D5711D5876D90L)   /*  247 */,
+            unchecked((long) 0x1F1A412891BC038EL)   /*  248 */,    unchecked((long) 0xD6E2E71D82E56648L)   /*  249 */,
+            unchecked((long) 0x74036C3A497732B7L)   /*  250 */,    unchecked((long) 0x89B67ED96361F5ABL)   /*  251 */,
+            unchecked((long) 0xFFED95D8F1EA02A2L)   /*  252 */,    unchecked((long) 0xE72B3BD61464D43DL)   /*  253 */,
+            unchecked((long) 0xA6300F170BDC4820L)   /*  254 */,    unchecked((long) 0xEBC18760ED78A77AL)   /*  255 */,
+        };
+
+        private static readonly long[] t2 = {
+            unchecked((long) 0xE6A6BE5A05A12138L)   /*  256 */,    unchecked((long) 0xB5A122A5B4F87C98L)   /*  257 */,
+            unchecked((long) 0x563C6089140B6990L)   /*  258 */,    unchecked((long) 0x4C46CB2E391F5DD5L)   /*  259 */,
+            unchecked((long) 0xD932ADDBC9B79434L)   /*  260 */,    unchecked((long) 0x08EA70E42015AFF5L)   /*  261 */,
+            unchecked((long) 0xD765A6673E478CF1L)   /*  262 */,    unchecked((long) 0xC4FB757EAB278D99L)   /*  263 */,
+            unchecked((long) 0xDF11C6862D6E0692L)   /*  264 */,    unchecked((long) 0xDDEB84F10D7F3B16L)   /*  265 */,
+            unchecked((long) 0x6F2EF604A665EA04L)   /*  266 */,    unchecked((long) 0x4A8E0F0FF0E0DFB3L)   /*  267 */,
+            unchecked((long) 0xA5EDEEF83DBCBA51L)   /*  268 */,    unchecked((long) 0xFC4F0A2A0EA4371EL)   /*  269 */,
+            unchecked((long) 0xE83E1DA85CB38429L)   /*  270 */,    unchecked((long) 0xDC8FF882BA1B1CE2L)   /*  271 */,
+            unchecked((long) 0xCD45505E8353E80DL)   /*  272 */,    unchecked((long) 0x18D19A00D4DB0717L)   /*  273 */,
+            unchecked((long) 0x34A0CFEDA5F38101L)   /*  274 */,    unchecked((long) 0x0BE77E518887CAF2L)   /*  275 */,
+            unchecked((long) 0x1E341438B3C45136L)   /*  276 */,    unchecked((long) 0xE05797F49089CCF9L)   /*  277 */,
+            unchecked((long) 0xFFD23F9DF2591D14L)   /*  278 */,    unchecked((long) 0x543DDA228595C5CDL)   /*  279 */,
+            unchecked((long) 0x661F81FD99052A33L)   /*  280 */,    unchecked((long) 0x8736E641DB0F7B76L)   /*  281 */,
+            unchecked((long) 0x15227725418E5307L)   /*  282 */,    unchecked((long) 0xE25F7F46162EB2FAL)   /*  283 */,
+            unchecked((long) 0x48A8B2126C13D9FEL)   /*  284 */,    unchecked((long) 0xAFDC541792E76EEAL)   /*  285 */,
+            unchecked((long) 0x03D912BFC6D1898FL)   /*  286 */,    unchecked((long) 0x31B1AAFA1B83F51BL)   /*  287 */,
+            unchecked((long) 0xF1AC2796E42AB7D9L)   /*  288 */,    unchecked((long) 0x40A3A7D7FCD2EBACL)   /*  289 */,
+            unchecked((long) 0x1056136D0AFBBCC5L)   /*  290 */,    unchecked((long) 0x7889E1DD9A6D0C85L)   /*  291 */,
+            unchecked((long) 0xD33525782A7974AAL)   /*  292 */,    unchecked((long) 0xA7E25D09078AC09BL)   /*  293 */,
+            unchecked((long) 0xBD4138B3EAC6EDD0L)   /*  294 */,    unchecked((long) 0x920ABFBE71EB9E70L)   /*  295 */,
+            unchecked((long) 0xA2A5D0F54FC2625CL)   /*  296 */,    unchecked((long) 0xC054E36B0B1290A3L)   /*  297 */,
+            unchecked((long) 0xF6DD59FF62FE932BL)   /*  298 */,    unchecked((long) 0x3537354511A8AC7DL)   /*  299 */,
+            unchecked((long) 0xCA845E9172FADCD4L)   /*  300 */,    unchecked((long) 0x84F82B60329D20DCL)   /*  301 */,
+            unchecked((long) 0x79C62CE1CD672F18L)   /*  302 */,    unchecked((long) 0x8B09A2ADD124642CL)   /*  303 */,
+            unchecked((long) 0xD0C1E96A19D9E726L)   /*  304 */,    unchecked((long) 0x5A786A9B4BA9500CL)   /*  305 */,
+            unchecked((long) 0x0E020336634C43F3L)   /*  306 */,    unchecked((long) 0xC17B474AEB66D822L)   /*  307 */,
+            unchecked((long) 0x6A731AE3EC9BAAC2L)   /*  308 */,    unchecked((long) 0x8226667AE0840258L)   /*  309 */,
+            unchecked((long) 0x67D4567691CAECA5L)   /*  310 */,    unchecked((long) 0x1D94155C4875ADB5L)   /*  311 */,
+            unchecked((long) 0x6D00FD985B813FDFL)   /*  312 */,    unchecked((long) 0x51286EFCB774CD06L)   /*  313 */,
+            unchecked((long) 0x5E8834471FA744AFL)   /*  314 */,    unchecked((long) 0xF72CA0AEE761AE2EL)   /*  315 */,
+            unchecked((long) 0xBE40E4CDAEE8E09AL)   /*  316 */,    unchecked((long) 0xE9970BBB5118F665L)   /*  317 */,
+            unchecked((long) 0x726E4BEB33DF1964L)   /*  318 */,    unchecked((long) 0x703B000729199762L)   /*  319 */,
+            unchecked((long) 0x4631D816F5EF30A7L)   /*  320 */,    unchecked((long) 0xB880B5B51504A6BEL)   /*  321 */,
+            unchecked((long) 0x641793C37ED84B6CL)   /*  322 */,    unchecked((long) 0x7B21ED77F6E97D96L)   /*  323 */,
+            unchecked((long) 0x776306312EF96B73L)   /*  324 */,    unchecked((long) 0xAE528948E86FF3F4L)   /*  325 */,
+            unchecked((long) 0x53DBD7F286A3F8F8L)   /*  326 */,    unchecked((long) 0x16CADCE74CFC1063L)   /*  327 */,
+            unchecked((long) 0x005C19BDFA52C6DDL)   /*  328 */,    unchecked((long) 0x68868F5D64D46AD3L)   /*  329 */,
+            unchecked((long) 0x3A9D512CCF1E186AL)   /*  330 */,    unchecked((long) 0x367E62C2385660AEL)   /*  331 */,
+            unchecked((long) 0xE359E7EA77DCB1D7L)   /*  332 */,    unchecked((long) 0x526C0773749ABE6EL)   /*  333 */,
+            unchecked((long) 0x735AE5F9D09F734BL)   /*  334 */,    unchecked((long) 0x493FC7CC8A558BA8L)   /*  335 */,
+            unchecked((long) 0xB0B9C1533041AB45L)   /*  336 */,    unchecked((long) 0x321958BA470A59BDL)   /*  337 */,
+            unchecked((long) 0x852DB00B5F46C393L)   /*  338 */,    unchecked((long) 0x91209B2BD336B0E5L)   /*  339 */,
+            unchecked((long) 0x6E604F7D659EF19FL)   /*  340 */,    unchecked((long) 0xB99A8AE2782CCB24L)   /*  341 */,
+            unchecked((long) 0xCCF52AB6C814C4C7L)   /*  342 */,    unchecked((long) 0x4727D9AFBE11727BL)   /*  343 */,
+            unchecked((long) 0x7E950D0C0121B34DL)   /*  344 */,    unchecked((long) 0x756F435670AD471FL)   /*  345 */,
+            unchecked((long) 0xF5ADD442615A6849L)   /*  346 */,    unchecked((long) 0x4E87E09980B9957AL)   /*  347 */,
+            unchecked((long) 0x2ACFA1DF50AEE355L)   /*  348 */,    unchecked((long) 0xD898263AFD2FD556L)   /*  349 */,
+            unchecked((long) 0xC8F4924DD80C8FD6L)   /*  350 */,    unchecked((long) 0xCF99CA3D754A173AL)   /*  351 */,
+            unchecked((long) 0xFE477BACAF91BF3CL)   /*  352 */,    unchecked((long) 0xED5371F6D690C12DL)   /*  353 */,
+            unchecked((long) 0x831A5C285E687094L)   /*  354 */,    unchecked((long) 0xC5D3C90A3708A0A4L)   /*  355 */,
+            unchecked((long) 0x0F7F903717D06580L)   /*  356 */,    unchecked((long) 0x19F9BB13B8FDF27FL)   /*  357 */,
+            unchecked((long) 0xB1BD6F1B4D502843L)   /*  358 */,    unchecked((long) 0x1C761BA38FFF4012L)   /*  359 */,
+            unchecked((long) 0x0D1530C4E2E21F3BL)   /*  360 */,    unchecked((long) 0x8943CE69A7372C8AL)   /*  361 */,
+            unchecked((long) 0xE5184E11FEB5CE66L)   /*  362 */,    unchecked((long) 0x618BDB80BD736621L)   /*  363 */,
+            unchecked((long) 0x7D29BAD68B574D0BL)   /*  364 */,    unchecked((long) 0x81BB613E25E6FE5BL)   /*  365 */,
+            unchecked((long) 0x071C9C10BC07913FL)   /*  366 */,    unchecked((long) 0xC7BEEB7909AC2D97L)   /*  367 */,
+            unchecked((long) 0xC3E58D353BC5D757L)   /*  368 */,    unchecked((long) 0xEB017892F38F61E8L)   /*  369 */,
+            unchecked((long) 0xD4EFFB9C9B1CC21AL)   /*  370 */,    unchecked((long) 0x99727D26F494F7ABL)   /*  371 */,
+            unchecked((long) 0xA3E063A2956B3E03L)   /*  372 */,    unchecked((long) 0x9D4A8B9A4AA09C30L)   /*  373 */,
+            unchecked((long) 0x3F6AB7D500090FB4L)   /*  374 */,    unchecked((long) 0x9CC0F2A057268AC0L)   /*  375 */,
+            unchecked((long) 0x3DEE9D2DEDBF42D1L)   /*  376 */,    unchecked((long) 0x330F49C87960A972L)   /*  377 */,
+            unchecked((long) 0xC6B2720287421B41L)   /*  378 */,    unchecked((long) 0x0AC59EC07C00369CL)   /*  379 */,
+            unchecked((long) 0xEF4EAC49CB353425L)   /*  380 */,    unchecked((long) 0xF450244EEF0129D8L)   /*  381 */,
+            unchecked((long) 0x8ACC46E5CAF4DEB6L)   /*  382 */,    unchecked((long) 0x2FFEAB63989263F7L)   /*  383 */,
+            unchecked((long) 0x8F7CB9FE5D7A4578L)   /*  384 */,    unchecked((long) 0x5BD8F7644E634635L)   /*  385 */,
+            unchecked((long) 0x427A7315BF2DC900L)   /*  386 */,    unchecked((long) 0x17D0C4AA2125261CL)   /*  387 */,
+            unchecked((long) 0x3992486C93518E50L)   /*  388 */,    unchecked((long) 0xB4CBFEE0A2D7D4C3L)   /*  389 */,
+            unchecked((long) 0x7C75D6202C5DDD8DL)   /*  390 */,    unchecked((long) 0xDBC295D8E35B6C61L)   /*  391 */,
+            unchecked((long) 0x60B369D302032B19L)   /*  392 */,    unchecked((long) 0xCE42685FDCE44132L)   /*  393 */,
+            unchecked((long) 0x06F3DDB9DDF65610L)   /*  394 */,    unchecked((long) 0x8EA4D21DB5E148F0L)   /*  395 */,
+            unchecked((long) 0x20B0FCE62FCD496FL)   /*  396 */,    unchecked((long) 0x2C1B912358B0EE31L)   /*  397 */,
+            unchecked((long) 0xB28317B818F5A308L)   /*  398 */,    unchecked((long) 0xA89C1E189CA6D2CFL)   /*  399 */,
+            unchecked((long) 0x0C6B18576AAADBC8L)   /*  400 */,    unchecked((long) 0xB65DEAA91299FAE3L)   /*  401 */,
+            unchecked((long) 0xFB2B794B7F1027E7L)   /*  402 */,    unchecked((long) 0x04E4317F443B5BEBL)   /*  403 */,
+            unchecked((long) 0x4B852D325939D0A6L)   /*  404 */,    unchecked((long) 0xD5AE6BEEFB207FFCL)   /*  405 */,
+            unchecked((long) 0x309682B281C7D374L)   /*  406 */,    unchecked((long) 0xBAE309A194C3B475L)   /*  407 */,
+            unchecked((long) 0x8CC3F97B13B49F05L)   /*  408 */,    unchecked((long) 0x98A9422FF8293967L)   /*  409 */,
+            unchecked((long) 0x244B16B01076FF7CL)   /*  410 */,    unchecked((long) 0xF8BF571C663D67EEL)   /*  411 */,
+            unchecked((long) 0x1F0D6758EEE30DA1L)   /*  412 */,    unchecked((long) 0xC9B611D97ADEB9B7L)   /*  413 */,
+            unchecked((long) 0xB7AFD5887B6C57A2L)   /*  414 */,    unchecked((long) 0x6290AE846B984FE1L)   /*  415 */,
+            unchecked((long) 0x94DF4CDEACC1A5FDL)   /*  416 */,    unchecked((long) 0x058A5BD1C5483AFFL)   /*  417 */,
+            unchecked((long) 0x63166CC142BA3C37L)   /*  418 */,    unchecked((long) 0x8DB8526EB2F76F40L)   /*  419 */,
+            unchecked((long) 0xE10880036F0D6D4EL)   /*  420 */,    unchecked((long) 0x9E0523C9971D311DL)   /*  421 */,
+            unchecked((long) 0x45EC2824CC7CD691L)   /*  422 */,    unchecked((long) 0x575B8359E62382C9L)   /*  423 */,
+            unchecked((long) 0xFA9E400DC4889995L)   /*  424 */,    unchecked((long) 0xD1823ECB45721568L)   /*  425 */,
+            unchecked((long) 0xDAFD983B8206082FL)   /*  426 */,    unchecked((long) 0xAA7D29082386A8CBL)   /*  427 */,
+            unchecked((long) 0x269FCD4403B87588L)   /*  428 */,    unchecked((long) 0x1B91F5F728BDD1E0L)   /*  429 */,
+            unchecked((long) 0xE4669F39040201F6L)   /*  430 */,    unchecked((long) 0x7A1D7C218CF04ADEL)   /*  431 */,
+            unchecked((long) 0x65623C29D79CE5CEL)   /*  432 */,    unchecked((long) 0x2368449096C00BB1L)   /*  433 */,
+            unchecked((long) 0xAB9BF1879DA503BAL)   /*  434 */,    unchecked((long) 0xBC23ECB1A458058EL)   /*  435 */,
+            unchecked((long) 0x9A58DF01BB401ECCL)   /*  436 */,    unchecked((long) 0xA070E868A85F143DL)   /*  437 */,
+            unchecked((long) 0x4FF188307DF2239EL)   /*  438 */,    unchecked((long) 0x14D565B41A641183L)   /*  439 */,
+            unchecked((long) 0xEE13337452701602L)   /*  440 */,    unchecked((long) 0x950E3DCF3F285E09L)   /*  441 */,
+            unchecked((long) 0x59930254B9C80953L)   /*  442 */,    unchecked((long) 0x3BF299408930DA6DL)   /*  443 */,
+            unchecked((long) 0xA955943F53691387L)   /*  444 */,    unchecked((long) 0xA15EDECAA9CB8784L)   /*  445 */,
+            unchecked((long) 0x29142127352BE9A0L)   /*  446 */,    unchecked((long) 0x76F0371FFF4E7AFBL)   /*  447 */,
+            unchecked((long) 0x0239F450274F2228L)   /*  448 */,    unchecked((long) 0xBB073AF01D5E868BL)   /*  449 */,
+            unchecked((long) 0xBFC80571C10E96C1L)   /*  450 */,    unchecked((long) 0xD267088568222E23L)   /*  451 */,
+            unchecked((long) 0x9671A3D48E80B5B0L)   /*  452 */,    unchecked((long) 0x55B5D38AE193BB81L)   /*  453 */,
+            unchecked((long) 0x693AE2D0A18B04B8L)   /*  454 */,    unchecked((long) 0x5C48B4ECADD5335FL)   /*  455 */,
+            unchecked((long) 0xFD743B194916A1CAL)   /*  456 */,    unchecked((long) 0x2577018134BE98C4L)   /*  457 */,
+            unchecked((long) 0xE77987E83C54A4ADL)   /*  458 */,    unchecked((long) 0x28E11014DA33E1B9L)   /*  459 */,
+            unchecked((long) 0x270CC59E226AA213L)   /*  460 */,    unchecked((long) 0x71495F756D1A5F60L)   /*  461 */,
+            unchecked((long) 0x9BE853FB60AFEF77L)   /*  462 */,    unchecked((long) 0xADC786A7F7443DBFL)   /*  463 */,
+            unchecked((long) 0x0904456173B29A82L)   /*  464 */,    unchecked((long) 0x58BC7A66C232BD5EL)   /*  465 */,
+            unchecked((long) 0xF306558C673AC8B2L)   /*  466 */,    unchecked((long) 0x41F639C6B6C9772AL)   /*  467 */,
+            unchecked((long) 0x216DEFE99FDA35DAL)   /*  468 */,    unchecked((long) 0x11640CC71C7BE615L)   /*  469 */,
+            unchecked((long) 0x93C43694565C5527L)   /*  470 */,    unchecked((long) 0xEA038E6246777839L)   /*  471 */,
+            unchecked((long) 0xF9ABF3CE5A3E2469L)   /*  472 */,    unchecked((long) 0x741E768D0FD312D2L)   /*  473 */,
+            unchecked((long) 0x0144B883CED652C6L)   /*  474 */,    unchecked((long) 0xC20B5A5BA33F8552L)   /*  475 */,
+            unchecked((long) 0x1AE69633C3435A9DL)   /*  476 */,    unchecked((long) 0x97A28CA4088CFDECL)   /*  477 */,
+            unchecked((long) 0x8824A43C1E96F420L)   /*  478 */,    unchecked((long) 0x37612FA66EEEA746L)   /*  479 */,
+            unchecked((long) 0x6B4CB165F9CF0E5AL)   /*  480 */,    unchecked((long) 0x43AA1C06A0ABFB4AL)   /*  481 */,
+            unchecked((long) 0x7F4DC26FF162796BL)   /*  482 */,    unchecked((long) 0x6CBACC8E54ED9B0FL)   /*  483 */,
+            unchecked((long) 0xA6B7FFEFD2BB253EL)   /*  484 */,    unchecked((long) 0x2E25BC95B0A29D4FL)   /*  485 */,
+            unchecked((long) 0x86D6A58BDEF1388CL)   /*  486 */,    unchecked((long) 0xDED74AC576B6F054L)   /*  487 */,
+            unchecked((long) 0x8030BDBC2B45805DL)   /*  488 */,    unchecked((long) 0x3C81AF70E94D9289L)   /*  489 */,
+            unchecked((long) 0x3EFF6DDA9E3100DBL)   /*  490 */,    unchecked((long) 0xB38DC39FDFCC8847L)   /*  491 */,
+            unchecked((long) 0x123885528D17B87EL)   /*  492 */,    unchecked((long) 0xF2DA0ED240B1B642L)   /*  493 */,
+            unchecked((long) 0x44CEFADCD54BF9A9L)   /*  494 */,    unchecked((long) 0x1312200E433C7EE6L)   /*  495 */,
+            unchecked((long) 0x9FFCC84F3A78C748L)   /*  496 */,    unchecked((long) 0xF0CD1F72248576BBL)   /*  497 */,
+            unchecked((long) 0xEC6974053638CFE4L)   /*  498 */,    unchecked((long) 0x2BA7B67C0CEC4E4CL)   /*  499 */,
+            unchecked((long) 0xAC2F4DF3E5CE32EDL)   /*  500 */,    unchecked((long) 0xCB33D14326EA4C11L)   /*  501 */,
+            unchecked((long) 0xA4E9044CC77E58BCL)   /*  502 */,    unchecked((long) 0x5F513293D934FCEFL)   /*  503 */,
+            unchecked((long) 0x5DC9645506E55444L)   /*  504 */,    unchecked((long) 0x50DE418F317DE40AL)   /*  505 */,
+            unchecked((long) 0x388CB31A69DDE259L)   /*  506 */,    unchecked((long) 0x2DB4A83455820A86L)   /*  507 */,
+            unchecked((long) 0x9010A91E84711AE9L)   /*  508 */,    unchecked((long) 0x4DF7F0B7B1498371L)   /*  509 */,
+            unchecked((long) 0xD62A2EABC0977179L)   /*  510 */,    unchecked((long) 0x22FAC097AA8D5C0EL)   /*  511 */,
+        };
+
+        private static readonly long[] t3 = {
+            unchecked((long) 0xF49FCC2FF1DAF39BL)   /*  512 */,    unchecked((long) 0x487FD5C66FF29281L)   /*  513 */,
+            unchecked((long) 0xE8A30667FCDCA83FL)   /*  514 */,    unchecked((long) 0x2C9B4BE3D2FCCE63L)   /*  515 */,
+            unchecked((long) 0xDA3FF74B93FBBBC2L)   /*  516 */,    unchecked((long) 0x2FA165D2FE70BA66L)   /*  517 */,
+            unchecked((long) 0xA103E279970E93D4L)   /*  518 */,    unchecked((long) 0xBECDEC77B0E45E71L)   /*  519 */,
+            unchecked((long) 0xCFB41E723985E497L)   /*  520 */,    unchecked((long) 0xB70AAA025EF75017L)   /*  521 */,
+            unchecked((long) 0xD42309F03840B8E0L)   /*  522 */,    unchecked((long) 0x8EFC1AD035898579L)   /*  523 */,
+            unchecked((long) 0x96C6920BE2B2ABC5L)   /*  524 */,    unchecked((long) 0x66AF4163375A9172L)   /*  525 */,
+            unchecked((long) 0x2174ABDCCA7127FBL)   /*  526 */,    unchecked((long) 0xB33CCEA64A72FF41L)   /*  527 */,
+            unchecked((long) 0xF04A4933083066A5L)   /*  528 */,    unchecked((long) 0x8D970ACDD7289AF5L)   /*  529 */,
+            unchecked((long) 0x8F96E8E031C8C25EL)   /*  530 */,    unchecked((long) 0xF3FEC02276875D47L)   /*  531 */,
+            unchecked((long) 0xEC7BF310056190DDL)   /*  532 */,    unchecked((long) 0xF5ADB0AEBB0F1491L)   /*  533 */,
+            unchecked((long) 0x9B50F8850FD58892L)   /*  534 */,    unchecked((long) 0x4975488358B74DE8L)   /*  535 */,
+            unchecked((long) 0xA3354FF691531C61L)   /*  536 */,    unchecked((long) 0x0702BBE481D2C6EEL)   /*  537 */,
+            unchecked((long) 0x89FB24057DEDED98L)   /*  538 */,    unchecked((long) 0xAC3075138596E902L)   /*  539 */,
+            unchecked((long) 0x1D2D3580172772EDL)   /*  540 */,    unchecked((long) 0xEB738FC28E6BC30DL)   /*  541 */,
+            unchecked((long) 0x5854EF8F63044326L)   /*  542 */,    unchecked((long) 0x9E5C52325ADD3BBEL)   /*  543 */,
+            unchecked((long) 0x90AA53CF325C4623L)   /*  544 */,    unchecked((long) 0xC1D24D51349DD067L)   /*  545 */,
+            unchecked((long) 0x2051CFEEA69EA624L)   /*  546 */,    unchecked((long) 0x13220F0A862E7E4FL)   /*  547 */,
+            unchecked((long) 0xCE39399404E04864L)   /*  548 */,    unchecked((long) 0xD9C42CA47086FCB7L)   /*  549 */,
+            unchecked((long) 0x685AD2238A03E7CCL)   /*  550 */,    unchecked((long) 0x066484B2AB2FF1DBL)   /*  551 */,
+            unchecked((long) 0xFE9D5D70EFBF79ECL)   /*  552 */,    unchecked((long) 0x5B13B9DD9C481854L)   /*  553 */,
+            unchecked((long) 0x15F0D475ED1509ADL)   /*  554 */,    unchecked((long) 0x0BEBCD060EC79851L)   /*  555 */,
+            unchecked((long) 0xD58C6791183AB7F8L)   /*  556 */,    unchecked((long) 0xD1187C5052F3EEE4L)   /*  557 */,
+            unchecked((long) 0xC95D1192E54E82FFL)   /*  558 */,    unchecked((long) 0x86EEA14CB9AC6CA2L)   /*  559 */,
+            unchecked((long) 0x3485BEB153677D5DL)   /*  560 */,    unchecked((long) 0xDD191D781F8C492AL)   /*  561 */,
+            unchecked((long) 0xF60866BAA784EBF9L)   /*  562 */,    unchecked((long) 0x518F643BA2D08C74L)   /*  563 */,
+            unchecked((long) 0x8852E956E1087C22L)   /*  564 */,    unchecked((long) 0xA768CB8DC410AE8DL)   /*  565 */,
+            unchecked((long) 0x38047726BFEC8E1AL)   /*  566 */,    unchecked((long) 0xA67738B4CD3B45AAL)   /*  567 */,
+            unchecked((long) 0xAD16691CEC0DDE19L)   /*  568 */,    unchecked((long) 0xC6D4319380462E07L)   /*  569 */,
+            unchecked((long) 0xC5A5876D0BA61938L)   /*  570 */,    unchecked((long) 0x16B9FA1FA58FD840L)   /*  571 */,
+            unchecked((long) 0x188AB1173CA74F18L)   /*  572 */,    unchecked((long) 0xABDA2F98C99C021FL)   /*  573 */,
+            unchecked((long) 0x3E0580AB134AE816L)   /*  574 */,    unchecked((long) 0x5F3B05B773645ABBL)   /*  575 */,
+            unchecked((long) 0x2501A2BE5575F2F6L)   /*  576 */,    unchecked((long) 0x1B2F74004E7E8BA9L)   /*  577 */,
+            unchecked((long) 0x1CD7580371E8D953L)   /*  578 */,    unchecked((long) 0x7F6ED89562764E30L)   /*  579 */,
+            unchecked((long) 0xB15926FF596F003DL)   /*  580 */,    unchecked((long) 0x9F65293DA8C5D6B9L)   /*  581 */,
+            unchecked((long) 0x6ECEF04DD690F84CL)   /*  582 */,    unchecked((long) 0x4782275FFF33AF88L)   /*  583 */,
+            unchecked((long) 0xE41433083F820801L)   /*  584 */,    unchecked((long) 0xFD0DFE409A1AF9B5L)   /*  585 */,
+            unchecked((long) 0x4325A3342CDB396BL)   /*  586 */,    unchecked((long) 0x8AE77E62B301B252L)   /*  587 */,
+            unchecked((long) 0xC36F9E9F6655615AL)   /*  588 */,    unchecked((long) 0x85455A2D92D32C09L)   /*  589 */,
+            unchecked((long) 0xF2C7DEA949477485L)   /*  590 */,    unchecked((long) 0x63CFB4C133A39EBAL)   /*  591 */,
+            unchecked((long) 0x83B040CC6EBC5462L)   /*  592 */,    unchecked((long) 0x3B9454C8FDB326B0L)   /*  593 */,
+            unchecked((long) 0x56F56A9E87FFD78CL)   /*  594 */,    unchecked((long) 0x2DC2940D99F42BC6L)   /*  595 */,
+            unchecked((long) 0x98F7DF096B096E2DL)   /*  596 */,    unchecked((long) 0x19A6E01E3AD852BFL)   /*  597 */,
+            unchecked((long) 0x42A99CCBDBD4B40BL)   /*  598 */,    unchecked((long) 0xA59998AF45E9C559L)   /*  599 */,
+            unchecked((long) 0x366295E807D93186L)   /*  600 */,    unchecked((long) 0x6B48181BFAA1F773L)   /*  601 */,
+            unchecked((long) 0x1FEC57E2157A0A1DL)   /*  602 */,    unchecked((long) 0x4667446AF6201AD5L)   /*  603 */,
+            unchecked((long) 0xE615EBCACFB0F075L)   /*  604 */,    unchecked((long) 0xB8F31F4F68290778L)   /*  605 */,
+            unchecked((long) 0x22713ED6CE22D11EL)   /*  606 */,    unchecked((long) 0x3057C1A72EC3C93BL)   /*  607 */,
+            unchecked((long) 0xCB46ACC37C3F1F2FL)   /*  608 */,    unchecked((long) 0xDBB893FD02AAF50EL)   /*  609 */,
+            unchecked((long) 0x331FD92E600B9FCFL)   /*  610 */,    unchecked((long) 0xA498F96148EA3AD6L)   /*  611 */,
+            unchecked((long) 0xA8D8426E8B6A83EAL)   /*  612 */,    unchecked((long) 0xA089B274B7735CDCL)   /*  613 */,
+            unchecked((long) 0x87F6B3731E524A11L)   /*  614 */,    unchecked((long) 0x118808E5CBC96749L)   /*  615 */,
+            unchecked((long) 0x9906E4C7B19BD394L)   /*  616 */,    unchecked((long) 0xAFED7F7E9B24A20CL)   /*  617 */,
+            unchecked((long) 0x6509EADEEB3644A7L)   /*  618 */,    unchecked((long) 0x6C1EF1D3E8EF0EDEL)   /*  619 */,
+            unchecked((long) 0xB9C97D43E9798FB4L)   /*  620 */,    unchecked((long) 0xA2F2D784740C28A3L)   /*  621 */,
+            unchecked((long) 0x7B8496476197566FL)   /*  622 */,    unchecked((long) 0x7A5BE3E6B65F069DL)   /*  623 */,
+            unchecked((long) 0xF96330ED78BE6F10L)   /*  624 */,    unchecked((long) 0xEEE60DE77A076A15L)   /*  625 */,
+            unchecked((long) 0x2B4BEE4AA08B9BD0L)   /*  626 */,    unchecked((long) 0x6A56A63EC7B8894EL)   /*  627 */,
+            unchecked((long) 0x02121359BA34FEF4L)   /*  628 */,    unchecked((long) 0x4CBF99F8283703FCL)   /*  629 */,
+            unchecked((long) 0x398071350CAF30C8L)   /*  630 */,    unchecked((long) 0xD0A77A89F017687AL)   /*  631 */,
+            unchecked((long) 0xF1C1A9EB9E423569L)   /*  632 */,    unchecked((long) 0x8C7976282DEE8199L)   /*  633 */,
+            unchecked((long) 0x5D1737A5DD1F7ABDL)   /*  634 */,    unchecked((long) 0x4F53433C09A9FA80L)   /*  635 */,
+            unchecked((long) 0xFA8B0C53DF7CA1D9L)   /*  636 */,    unchecked((long) 0x3FD9DCBC886CCB77L)   /*  637 */,
+            unchecked((long) 0xC040917CA91B4720L)   /*  638 */,    unchecked((long) 0x7DD00142F9D1DCDFL)   /*  639 */,
+            unchecked((long) 0x8476FC1D4F387B58L)   /*  640 */,    unchecked((long) 0x23F8E7C5F3316503L)   /*  641 */,
+            unchecked((long) 0x032A2244E7E37339L)   /*  642 */,    unchecked((long) 0x5C87A5D750F5A74BL)   /*  643 */,
+            unchecked((long) 0x082B4CC43698992EL)   /*  644 */,    unchecked((long) 0xDF917BECB858F63CL)   /*  645 */,
+            unchecked((long) 0x3270B8FC5BF86DDAL)   /*  646 */,    unchecked((long) 0x10AE72BB29B5DD76L)   /*  647 */,
+            unchecked((long) 0x576AC94E7700362BL)   /*  648 */,    unchecked((long) 0x1AD112DAC61EFB8FL)   /*  649 */,
+            unchecked((long) 0x691BC30EC5FAA427L)   /*  650 */,    unchecked((long) 0xFF246311CC327143L)   /*  651 */,
+            unchecked((long) 0x3142368E30E53206L)   /*  652 */,    unchecked((long) 0x71380E31E02CA396L)   /*  653 */,
+            unchecked((long) 0x958D5C960AAD76F1L)   /*  654 */,    unchecked((long) 0xF8D6F430C16DA536L)   /*  655 */,
+            unchecked((long) 0xC8FFD13F1BE7E1D2L)   /*  656 */,    unchecked((long) 0x7578AE66004DDBE1L)   /*  657 */,
+            unchecked((long) 0x05833F01067BE646L)   /*  658 */,    unchecked((long) 0xBB34B5AD3BFE586DL)   /*  659 */,
+            unchecked((long) 0x095F34C9A12B97F0L)   /*  660 */,    unchecked((long) 0x247AB64525D60CA8L)   /*  661 */,
+            unchecked((long) 0xDCDBC6F3017477D1L)   /*  662 */,    unchecked((long) 0x4A2E14D4DECAD24DL)   /*  663 */,
+            unchecked((long) 0xBDB5E6D9BE0A1EEBL)   /*  664 */,    unchecked((long) 0x2A7E70F7794301ABL)   /*  665 */,
+            unchecked((long) 0xDEF42D8A270540FDL)   /*  666 */,    unchecked((long) 0x01078EC0A34C22C1L)   /*  667 */,
+            unchecked((long) 0xE5DE511AF4C16387L)   /*  668 */,    unchecked((long) 0x7EBB3A52BD9A330AL)   /*  669 */,
+            unchecked((long) 0x77697857AA7D6435L)   /*  670 */,    unchecked((long) 0x004E831603AE4C32L)   /*  671 */,
+            unchecked((long) 0xE7A21020AD78E312L)   /*  672 */,    unchecked((long) 0x9D41A70C6AB420F2L)   /*  673 */,
+            unchecked((long) 0x28E06C18EA1141E6L)   /*  674 */,    unchecked((long) 0xD2B28CBD984F6B28L)   /*  675 */,
+            unchecked((long) 0x26B75F6C446E9D83L)   /*  676 */,    unchecked((long) 0xBA47568C4D418D7FL)   /*  677 */,
+            unchecked((long) 0xD80BADBFE6183D8EL)   /*  678 */,    unchecked((long) 0x0E206D7F5F166044L)   /*  679 */,
+            unchecked((long) 0xE258A43911CBCA3EL)   /*  680 */,    unchecked((long) 0x723A1746B21DC0BCL)   /*  681 */,
+            unchecked((long) 0xC7CAA854F5D7CDD3L)   /*  682 */,    unchecked((long) 0x7CAC32883D261D9CL)   /*  683 */,
+            unchecked((long) 0x7690C26423BA942CL)   /*  684 */,    unchecked((long) 0x17E55524478042B8L)   /*  685 */,
+            unchecked((long) 0xE0BE477656A2389FL)   /*  686 */,    unchecked((long) 0x4D289B5E67AB2DA0L)   /*  687 */,
+            unchecked((long) 0x44862B9C8FBBFD31L)   /*  688 */,    unchecked((long) 0xB47CC8049D141365L)   /*  689 */,
+            unchecked((long) 0x822C1B362B91C793L)   /*  690 */,    unchecked((long) 0x4EB14655FB13DFD8L)   /*  691 */,
+            unchecked((long) 0x1ECBBA0714E2A97BL)   /*  692 */,    unchecked((long) 0x6143459D5CDE5F14L)   /*  693 */,
+            unchecked((long) 0x53A8FBF1D5F0AC89L)   /*  694 */,    unchecked((long) 0x97EA04D81C5E5B00L)   /*  695 */,
+            unchecked((long) 0x622181A8D4FDB3F3L)   /*  696 */,    unchecked((long) 0xE9BCD341572A1208L)   /*  697 */,
+            unchecked((long) 0x1411258643CCE58AL)   /*  698 */,    unchecked((long) 0x9144C5FEA4C6E0A4L)   /*  699 */,
+            unchecked((long) 0x0D33D06565CF620FL)   /*  700 */,    unchecked((long) 0x54A48D489F219CA1L)   /*  701 */,
+            unchecked((long) 0xC43E5EAC6D63C821L)   /*  702 */,    unchecked((long) 0xA9728B3A72770DAFL)   /*  703 */,
+            unchecked((long) 0xD7934E7B20DF87EFL)   /*  704 */,    unchecked((long) 0xE35503B61A3E86E5L)   /*  705 */,
+            unchecked((long) 0xCAE321FBC819D504L)   /*  706 */,    unchecked((long) 0x129A50B3AC60BFA6L)   /*  707 */,
+            unchecked((long) 0xCD5E68EA7E9FB6C3L)   /*  708 */,    unchecked((long) 0xB01C90199483B1C7L)   /*  709 */,
+            unchecked((long) 0x3DE93CD5C295376CL)   /*  710 */,    unchecked((long) 0xAED52EDF2AB9AD13L)   /*  711 */,
+            unchecked((long) 0x2E60F512C0A07884L)   /*  712 */,    unchecked((long) 0xBC3D86A3E36210C9L)   /*  713 */,
+            unchecked((long) 0x35269D9B163951CEL)   /*  714 */,    unchecked((long) 0x0C7D6E2AD0CDB5FAL)   /*  715 */,
+            unchecked((long) 0x59E86297D87F5733L)   /*  716 */,    unchecked((long) 0x298EF221898DB0E7L)   /*  717 */,
+            unchecked((long) 0x55000029D1A5AA7EL)   /*  718 */,    unchecked((long) 0x8BC08AE1B5061B45L)   /*  719 */,
+            unchecked((long) 0xC2C31C2B6C92703AL)   /*  720 */,    unchecked((long) 0x94CC596BAF25EF42L)   /*  721 */,
+            unchecked((long) 0x0A1D73DB22540456L)   /*  722 */,    unchecked((long) 0x04B6A0F9D9C4179AL)   /*  723 */,
+            unchecked((long) 0xEFFDAFA2AE3D3C60L)   /*  724 */,    unchecked((long) 0xF7C8075BB49496C4L)   /*  725 */,
+            unchecked((long) 0x9CC5C7141D1CD4E3L)   /*  726 */,    unchecked((long) 0x78BD1638218E5534L)   /*  727 */,
+            unchecked((long) 0xB2F11568F850246AL)   /*  728 */,    unchecked((long) 0xEDFABCFA9502BC29L)   /*  729 */,
+            unchecked((long) 0x796CE5F2DA23051BL)   /*  730 */,    unchecked((long) 0xAAE128B0DC93537CL)   /*  731 */,
+            unchecked((long) 0x3A493DA0EE4B29AEL)   /*  732 */,    unchecked((long) 0xB5DF6B2C416895D7L)   /*  733 */,
+            unchecked((long) 0xFCABBD25122D7F37L)   /*  734 */,    unchecked((long) 0x70810B58105DC4B1L)   /*  735 */,
+            unchecked((long) 0xE10FDD37F7882A90L)   /*  736 */,    unchecked((long) 0x524DCAB5518A3F5CL)   /*  737 */,
+            unchecked((long) 0x3C9E85878451255BL)   /*  738 */,    unchecked((long) 0x4029828119BD34E2L)   /*  739 */,
+            unchecked((long) 0x74A05B6F5D3CECCBL)   /*  740 */,    unchecked((long) 0xB610021542E13ECAL)   /*  741 */,
+            unchecked((long) 0x0FF979D12F59E2ACL)   /*  742 */,    unchecked((long) 0x6037DA27E4F9CC50L)   /*  743 */,
+            unchecked((long) 0x5E92975A0DF1847DL)   /*  744 */,    unchecked((long) 0xD66DE190D3E623FEL)   /*  745 */,
+            unchecked((long) 0x5032D6B87B568048L)   /*  746 */,    unchecked((long) 0x9A36B7CE8235216EL)   /*  747 */,
+            unchecked((long) 0x80272A7A24F64B4AL)   /*  748 */,    unchecked((long) 0x93EFED8B8C6916F7L)   /*  749 */,
+            unchecked((long) 0x37DDBFF44CCE1555L)   /*  750 */,    unchecked((long) 0x4B95DB5D4B99BD25L)   /*  751 */,
+            unchecked((long) 0x92D3FDA169812FC0L)   /*  752 */,    unchecked((long) 0xFB1A4A9A90660BB6L)   /*  753 */,
+            unchecked((long) 0x730C196946A4B9B2L)   /*  754 */,    unchecked((long) 0x81E289AA7F49DA68L)   /*  755 */,
+            unchecked((long) 0x64669A0F83B1A05FL)   /*  756 */,    unchecked((long) 0x27B3FF7D9644F48BL)   /*  757 */,
+            unchecked((long) 0xCC6B615C8DB675B3L)   /*  758 */,    unchecked((long) 0x674F20B9BCEBBE95L)   /*  759 */,
+            unchecked((long) 0x6F31238275655982L)   /*  760 */,    unchecked((long) 0x5AE488713E45CF05L)   /*  761 */,
+            unchecked((long) 0xBF619F9954C21157L)   /*  762 */,    unchecked((long) 0xEABAC46040A8EAE9L)   /*  763 */,
+            unchecked((long) 0x454C6FE9F2C0C1CDL)   /*  764 */,    unchecked((long) 0x419CF6496412691CL)   /*  765 */,
+            unchecked((long) 0xD3DC3BEF265B0F70L)   /*  766 */,    unchecked((long) 0x6D0E60F5C3578A9EL)   /*  767 */,
+        };
+
+        private static readonly long[] t4 = {
+            unchecked((long) 0x5B0E608526323C55L)   /*  768 */,    unchecked((long) 0x1A46C1A9FA1B59F5L)   /*  769 */,
+            unchecked((long) 0xA9E245A17C4C8FFAL)   /*  770 */,    unchecked((long) 0x65CA5159DB2955D7L)   /*  771 */,
+            unchecked((long) 0x05DB0A76CE35AFC2L)   /*  772 */,    unchecked((long) 0x81EAC77EA9113D45L)   /*  773 */,
+            unchecked((long) 0x528EF88AB6AC0A0DL)   /*  774 */,    unchecked((long) 0xA09EA253597BE3FFL)   /*  775 */,
+            unchecked((long) 0x430DDFB3AC48CD56L)   /*  776 */,    unchecked((long) 0xC4B3A67AF45CE46FL)   /*  777 */,
+            unchecked((long) 0x4ECECFD8FBE2D05EL)   /*  778 */,    unchecked((long) 0x3EF56F10B39935F0L)   /*  779 */,
+            unchecked((long) 0x0B22D6829CD619C6L)   /*  780 */,    unchecked((long) 0x17FD460A74DF2069L)   /*  781 */,
+            unchecked((long) 0x6CF8CC8E8510ED40L)   /*  782 */,    unchecked((long) 0xD6C824BF3A6ECAA7L)   /*  783 */,
+            unchecked((long) 0x61243D581A817049L)   /*  784 */,    unchecked((long) 0x048BACB6BBC163A2L)   /*  785 */,
+            unchecked((long) 0xD9A38AC27D44CC32L)   /*  786 */,    unchecked((long) 0x7FDDFF5BAAF410ABL)   /*  787 */,
+            unchecked((long) 0xAD6D495AA804824BL)   /*  788 */,    unchecked((long) 0xE1A6A74F2D8C9F94L)   /*  789 */,
+            unchecked((long) 0xD4F7851235DEE8E3L)   /*  790 */,    unchecked((long) 0xFD4B7F886540D893L)   /*  791 */,
+            unchecked((long) 0x247C20042AA4BFDAL)   /*  792 */,    unchecked((long) 0x096EA1C517D1327CL)   /*  793 */,
+            unchecked((long) 0xD56966B4361A6685L)   /*  794 */,    unchecked((long) 0x277DA5C31221057DL)   /*  795 */,
+            unchecked((long) 0x94D59893A43ACFF7L)   /*  796 */,    unchecked((long) 0x64F0C51CCDC02281L)   /*  797 */,
+            unchecked((long) 0x3D33BCC4FF6189DBL)   /*  798 */,    unchecked((long) 0xE005CB184CE66AF1L)   /*  799 */,
+            unchecked((long) 0xFF5CCD1D1DB99BEAL)   /*  800 */,    unchecked((long) 0xB0B854A7FE42980FL)   /*  801 */,
+            unchecked((long) 0x7BD46A6A718D4B9FL)   /*  802 */,    unchecked((long) 0xD10FA8CC22A5FD8CL)   /*  803 */,
+            unchecked((long) 0xD31484952BE4BD31L)   /*  804 */,    unchecked((long) 0xC7FA975FCB243847L)   /*  805 */,
+            unchecked((long) 0x4886ED1E5846C407L)   /*  806 */,    unchecked((long) 0x28CDDB791EB70B04L)   /*  807 */,
+            unchecked((long) 0xC2B00BE2F573417FL)   /*  808 */,    unchecked((long) 0x5C9590452180F877L)   /*  809 */,
+            unchecked((long) 0x7A6BDDFFF370EB00L)   /*  810 */,    unchecked((long) 0xCE509E38D6D9D6A4L)   /*  811 */,
+            unchecked((long) 0xEBEB0F00647FA702L)   /*  812 */,    unchecked((long) 0x1DCC06CF76606F06L)   /*  813 */,
+            unchecked((long) 0xE4D9F28BA286FF0AL)   /*  814 */,    unchecked((long) 0xD85A305DC918C262L)   /*  815 */,
+            unchecked((long) 0x475B1D8732225F54L)   /*  816 */,    unchecked((long) 0x2D4FB51668CCB5FEL)   /*  817 */,
+            unchecked((long) 0xA679B9D9D72BBA20L)   /*  818 */,    unchecked((long) 0x53841C0D912D43A5L)   /*  819 */,
+            unchecked((long) 0x3B7EAA48BF12A4E8L)   /*  820 */,    unchecked((long) 0x781E0E47F22F1DDFL)   /*  821 */,
+            unchecked((long) 0xEFF20CE60AB50973L)   /*  822 */,    unchecked((long) 0x20D261D19DFFB742L)   /*  823 */,
+            unchecked((long) 0x16A12B03062A2E39L)   /*  824 */,    unchecked((long) 0x1960EB2239650495L)   /*  825 */,
+            unchecked((long) 0x251C16FED50EB8B8L)   /*  826 */,    unchecked((long) 0x9AC0C330F826016EL)   /*  827 */,
+            unchecked((long) 0xED152665953E7671L)   /*  828 */,    unchecked((long) 0x02D63194A6369570L)   /*  829 */,
+            unchecked((long) 0x5074F08394B1C987L)   /*  830 */,    unchecked((long) 0x70BA598C90B25CE1L)   /*  831 */,
+            unchecked((long) 0x794A15810B9742F6L)   /*  832 */,    unchecked((long) 0x0D5925E9FCAF8C6CL)   /*  833 */,
+            unchecked((long) 0x3067716CD868744EL)   /*  834 */,    unchecked((long) 0x910AB077E8D7731BL)   /*  835 */,
+            unchecked((long) 0x6A61BBDB5AC42F61L)   /*  836 */,    unchecked((long) 0x93513EFBF0851567L)   /*  837 */,
+            unchecked((long) 0xF494724B9E83E9D5L)   /*  838 */,    unchecked((long) 0xE887E1985C09648DL)   /*  839 */,
+            unchecked((long) 0x34B1D3C675370CFDL)   /*  840 */,    unchecked((long) 0xDC35E433BC0D255DL)   /*  841 */,
+            unchecked((long) 0xD0AAB84234131BE0L)   /*  842 */,    unchecked((long) 0x08042A50B48B7EAFL)   /*  843 */,
+            unchecked((long) 0x9997C4EE44A3AB35L)   /*  844 */,    unchecked((long) 0x829A7B49201799D0L)   /*  845 */,
+            unchecked((long) 0x263B8307B7C54441L)   /*  846 */,    unchecked((long) 0x752F95F4FD6A6CA6L)   /*  847 */,
+            unchecked((long) 0x927217402C08C6E5L)   /*  848 */,    unchecked((long) 0x2A8AB754A795D9EEL)   /*  849 */,
+            unchecked((long) 0xA442F7552F72943DL)   /*  850 */,    unchecked((long) 0x2C31334E19781208L)   /*  851 */,
+            unchecked((long) 0x4FA98D7CEAEE6291L)   /*  852 */,    unchecked((long) 0x55C3862F665DB309L)   /*  853 */,
+            unchecked((long) 0xBD0610175D53B1F3L)   /*  854 */,    unchecked((long) 0x46FE6CB840413F27L)   /*  855 */,
+            unchecked((long) 0x3FE03792DF0CFA59L)   /*  856 */,    unchecked((long) 0xCFE700372EB85E8FL)   /*  857 */,
+            unchecked((long) 0xA7BE29E7ADBCE118L)   /*  858 */,    unchecked((long) 0xE544EE5CDE8431DDL)   /*  859 */,
+            unchecked((long) 0x8A781B1B41F1873EL)   /*  860 */,    unchecked((long) 0xA5C94C78A0D2F0E7L)   /*  861 */,
+            unchecked((long) 0x39412E2877B60728L)   /*  862 */,    unchecked((long) 0xA1265EF3AFC9A62CL)   /*  863 */,
+            unchecked((long) 0xBCC2770C6A2506C5L)   /*  864 */,    unchecked((long) 0x3AB66DD5DCE1CE12L)   /*  865 */,
+            unchecked((long) 0xE65499D04A675B37L)   /*  866 */,    unchecked((long) 0x7D8F523481BFD216L)   /*  867 */,
+            unchecked((long) 0x0F6F64FCEC15F389L)   /*  868 */,    unchecked((long) 0x74EFBE618B5B13C8L)   /*  869 */,
+            unchecked((long) 0xACDC82B714273E1DL)   /*  870 */,    unchecked((long) 0xDD40BFE003199D17L)   /*  871 */,
+            unchecked((long) 0x37E99257E7E061F8L)   /*  872 */,    unchecked((long) 0xFA52626904775AAAL)   /*  873 */,
+            unchecked((long) 0x8BBBF63A463D56F9L)   /*  874 */,    unchecked((long) 0xF0013F1543A26E64L)   /*  875 */,
+            unchecked((long) 0xA8307E9F879EC898L)   /*  876 */,    unchecked((long) 0xCC4C27A4150177CCL)   /*  877 */,
+            unchecked((long) 0x1B432F2CCA1D3348L)   /*  878 */,    unchecked((long) 0xDE1D1F8F9F6FA013L)   /*  879 */,
+            unchecked((long) 0x606602A047A7DDD6L)   /*  880 */,    unchecked((long) 0xD237AB64CC1CB2C7L)   /*  881 */,
+            unchecked((long) 0x9B938E7225FCD1D3L)   /*  882 */,    unchecked((long) 0xEC4E03708E0FF476L)   /*  883 */,
+            unchecked((long) 0xFEB2FBDA3D03C12DL)   /*  884 */,    unchecked((long) 0xAE0BCED2EE43889AL)   /*  885 */,
+            unchecked((long) 0x22CB8923EBFB4F43L)   /*  886 */,    unchecked((long) 0x69360D013CF7396DL)   /*  887 */,
+            unchecked((long) 0x855E3602D2D4E022L)   /*  888 */,    unchecked((long) 0x073805BAD01F784CL)   /*  889 */,
+            unchecked((long) 0x33E17A133852F546L)   /*  890 */,    unchecked((long) 0xDF4874058AC7B638L)   /*  891 */,
+            unchecked((long) 0xBA92B29C678AA14AL)   /*  892 */,    unchecked((long) 0x0CE89FC76CFAADCDL)   /*  893 */,
+            unchecked((long) 0x5F9D4E0908339E34L)   /*  894 */,    unchecked((long) 0xF1AFE9291F5923B9L)   /*  895 */,
+            unchecked((long) 0x6E3480F60F4A265FL)   /*  896 */,    unchecked((long) 0xEEBF3A2AB29B841CL)   /*  897 */,
+            unchecked((long) 0xE21938A88F91B4ADL)   /*  898 */,    unchecked((long) 0x57DFEFF845C6D3C3L)   /*  899 */,
+            unchecked((long) 0x2F006B0BF62CAAF2L)   /*  900 */,    unchecked((long) 0x62F479EF6F75EE78L)   /*  901 */,
+            unchecked((long) 0x11A55AD41C8916A9L)   /*  902 */,    unchecked((long) 0xF229D29084FED453L)   /*  903 */,
+            unchecked((long) 0x42F1C27B16B000E6L)   /*  904 */,    unchecked((long) 0x2B1F76749823C074L)   /*  905 */,
+            unchecked((long) 0x4B76ECA3C2745360L)   /*  906 */,    unchecked((long) 0x8C98F463B91691BDL)   /*  907 */,
+            unchecked((long) 0x14BCC93CF1ADE66AL)   /*  908 */,    unchecked((long) 0x8885213E6D458397L)   /*  909 */,
+            unchecked((long) 0x8E177DF0274D4711L)   /*  910 */,    unchecked((long) 0xB49B73B5503F2951L)   /*  911 */,
+            unchecked((long) 0x10168168C3F96B6BL)   /*  912 */,    unchecked((long) 0x0E3D963B63CAB0AEL)   /*  913 */,
+            unchecked((long) 0x8DFC4B5655A1DB14L)   /*  914 */,    unchecked((long) 0xF789F1356E14DE5CL)   /*  915 */,
+            unchecked((long) 0x683E68AF4E51DAC1L)   /*  916 */,    unchecked((long) 0xC9A84F9D8D4B0FD9L)   /*  917 */,
+            unchecked((long) 0x3691E03F52A0F9D1L)   /*  918 */,    unchecked((long) 0x5ED86E46E1878E80L)   /*  919 */,
+            unchecked((long) 0x3C711A0E99D07150L)   /*  920 */,    unchecked((long) 0x5A0865B20C4E9310L)   /*  921 */,
+            unchecked((long) 0x56FBFC1FE4F0682EL)   /*  922 */,    unchecked((long) 0xEA8D5DE3105EDF9BL)   /*  923 */,
+            unchecked((long) 0x71ABFDB12379187AL)   /*  924 */,    unchecked((long) 0x2EB99DE1BEE77B9CL)   /*  925 */,
+            unchecked((long) 0x21ECC0EA33CF4523L)   /*  926 */,    unchecked((long) 0x59A4D7521805C7A1L)   /*  927 */,
+            unchecked((long) 0x3896F5EB56AE7C72L)   /*  928 */,    unchecked((long) 0xAA638F3DB18F75DCL)   /*  929 */,
+            unchecked((long) 0x9F39358DABE9808EL)   /*  930 */,    unchecked((long) 0xB7DEFA91C00B72ACL)   /*  931 */,
+            unchecked((long) 0x6B5541FD62492D92L)   /*  932 */,    unchecked((long) 0x6DC6DEE8F92E4D5BL)   /*  933 */,
+            unchecked((long) 0x353F57ABC4BEEA7EL)   /*  934 */,    unchecked((long) 0x735769D6DA5690CEL)   /*  935 */,
+            unchecked((long) 0x0A234AA642391484L)   /*  936 */,    unchecked((long) 0xF6F9508028F80D9DL)   /*  937 */,
+            unchecked((long) 0xB8E319A27AB3F215L)   /*  938 */,    unchecked((long) 0x31AD9C1151341A4DL)   /*  939 */,
+            unchecked((long) 0x773C22A57BEF5805L)   /*  940 */,    unchecked((long) 0x45C7561A07968633L)   /*  941 */,
+            unchecked((long) 0xF913DA9E249DBE36L)   /*  942 */,    unchecked((long) 0xDA652D9B78A64C68L)   /*  943 */,
+            unchecked((long) 0x4C27A97F3BC334EFL)   /*  944 */,    unchecked((long) 0x76621220E66B17F4L)   /*  945 */,
+            unchecked((long) 0x967743899ACD7D0BL)   /*  946 */,    unchecked((long) 0xF3EE5BCAE0ED6782L)   /*  947 */,
+            unchecked((long) 0x409F753600C879FCL)   /*  948 */,    unchecked((long) 0x06D09A39B5926DB6L)   /*  949 */,
+            unchecked((long) 0x6F83AEB0317AC588L)   /*  950 */,    unchecked((long) 0x01E6CA4A86381F21L)   /*  951 */,
+            unchecked((long) 0x66FF3462D19F3025L)   /*  952 */,    unchecked((long) 0x72207C24DDFD3BFBL)   /*  953 */,
+            unchecked((long) 0x4AF6B6D3E2ECE2EBL)   /*  954 */,    unchecked((long) 0x9C994DBEC7EA08DEL)   /*  955 */,
+            unchecked((long) 0x49ACE597B09A8BC4L)   /*  956 */,    unchecked((long) 0xB38C4766CF0797BAL)   /*  957 */,
+            unchecked((long) 0x131B9373C57C2A75L)   /*  958 */,    unchecked((long) 0xB1822CCE61931E58L)   /*  959 */,
+            unchecked((long) 0x9D7555B909BA1C0CL)   /*  960 */,    unchecked((long) 0x127FAFDD937D11D2L)   /*  961 */,
+            unchecked((long) 0x29DA3BADC66D92E4L)   /*  962 */,    unchecked((long) 0xA2C1D57154C2ECBCL)   /*  963 */,
+            unchecked((long) 0x58C5134D82F6FE24L)   /*  964 */,    unchecked((long) 0x1C3AE3515B62274FL)   /*  965 */,
+            unchecked((long) 0xE907C82E01CB8126L)   /*  966 */,    unchecked((long) 0xF8ED091913E37FCBL)   /*  967 */,
+            unchecked((long) 0x3249D8F9C80046C9L)   /*  968 */,    unchecked((long) 0x80CF9BEDE388FB63L)   /*  969 */,
+            unchecked((long) 0x1881539A116CF19EL)   /*  970 */,    unchecked((long) 0x5103F3F76BD52457L)   /*  971 */,
+            unchecked((long) 0x15B7E6F5AE47F7A8L)   /*  972 */,    unchecked((long) 0xDBD7C6DED47E9CCFL)   /*  973 */,
+            unchecked((long) 0x44E55C410228BB1AL)   /*  974 */,    unchecked((long) 0xB647D4255EDB4E99L)   /*  975 */,
+            unchecked((long) 0x5D11882BB8AAFC30L)   /*  976 */,    unchecked((long) 0xF5098BBB29D3212AL)   /*  977 */,
+            unchecked((long) 0x8FB5EA14E90296B3L)   /*  978 */,    unchecked((long) 0x677B942157DD025AL)   /*  979 */,
+            unchecked((long) 0xFB58E7C0A390ACB5L)   /*  980 */,    unchecked((long) 0x89D3674C83BD4A01L)   /*  981 */,
+            unchecked((long) 0x9E2DA4DF4BF3B93BL)   /*  982 */,    unchecked((long) 0xFCC41E328CAB4829L)   /*  983 */,
+            unchecked((long) 0x03F38C96BA582C52L)   /*  984 */,    unchecked((long) 0xCAD1BDBD7FD85DB2L)   /*  985 */,
+            unchecked((long) 0xBBB442C16082AE83L)   /*  986 */,    unchecked((long) 0xB95FE86BA5DA9AB0L)   /*  987 */,
+            unchecked((long) 0xB22E04673771A93FL)   /*  988 */,    unchecked((long) 0x845358C9493152D8L)   /*  989 */,
+            unchecked((long) 0xBE2A488697B4541EL)   /*  990 */,    unchecked((long) 0x95A2DC2DD38E6966L)   /*  991 */,
+            unchecked((long) 0xC02C11AC923C852BL)   /*  992 */,    unchecked((long) 0x2388B1990DF2A87BL)   /*  993 */,
+            unchecked((long) 0x7C8008FA1B4F37BEL)   /*  994 */,    unchecked((long) 0x1F70D0C84D54E503L)   /*  995 */,
+            unchecked((long) 0x5490ADEC7ECE57D4L)   /*  996 */,    unchecked((long) 0x002B3C27D9063A3AL)   /*  997 */,
+            unchecked((long) 0x7EAEA3848030A2BFL)   /*  998 */,    unchecked((long) 0xC602326DED2003C0L)   /*  999 */,
+            unchecked((long) 0x83A7287D69A94086L)   /* 1000 */,    unchecked((long) 0xC57A5FCB30F57A8AL)   /* 1001 */,
+            unchecked((long) 0xB56844E479EBE779L)   /* 1002 */,    unchecked((long) 0xA373B40F05DCBCE9L)   /* 1003 */,
+            unchecked((long) 0xD71A786E88570EE2L)   /* 1004 */,    unchecked((long) 0x879CBACDBDE8F6A0L)   /* 1005 */,
+            unchecked((long) 0x976AD1BCC164A32FL)   /* 1006 */,    unchecked((long) 0xAB21E25E9666D78BL)   /* 1007 */,
+            unchecked((long) 0x901063AAE5E5C33CL)   /* 1008 */,    unchecked((long) 0x9818B34448698D90L)   /* 1009 */,
+            unchecked((long) 0xE36487AE3E1E8ABBL)   /* 1010 */,    unchecked((long) 0xAFBDF931893BDCB4L)   /* 1011 */,
+            unchecked((long) 0x6345A0DC5FBBD519L)   /* 1012 */,    unchecked((long) 0x8628FE269B9465CAL)   /* 1013 */,
+            unchecked((long) 0x1E5D01603F9C51ECL)   /* 1014 */,    unchecked((long) 0x4DE44006A15049B7L)   /* 1015 */,
+            unchecked((long) 0xBF6C70E5F776CBB1L)   /* 1016 */,    unchecked((long) 0x411218F2EF552BEDL)   /* 1017 */,
+            unchecked((long) 0xCB0C0708705A36A3L)   /* 1018 */,    unchecked((long) 0xE74D14754F986044L)   /* 1019 */,
+            unchecked((long) 0xCD56D9430EA8280EL)   /* 1020 */,    unchecked((long) 0xC12591D7535F5065L)   /* 1021 */,
+            unchecked((long) 0xC83223F1720AEF96L)   /* 1022 */,    unchecked((long) 0xC3A0396F7363A51FL)   /* 1023 */
+        };
+
+        private const int    DigestLength = 24;
+
+        //
+        // registers
+        //
+        private long    a, b, c;
+        private long    byteCount;
+
+        //
+        // buffers
+        //
+        private byte[]  Buffer = new byte[8];
+        private int     bOff;
+
+        private long[]  x = new long[8];
+        private int     xOff;
+
+        /**
+        * Standard constructor
+        */
+        public TigerDigest()
+        {
+            Reset();
+        }
+
+        /**
+        * Copy constructor.  This will copy the state of the provided
+        * message digest.
+        */
+        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;
+        }
+
+		public string AlgorithmName
+		{
+			get { return "Tiger"; }
+		}
+
+		public int GetDigestSize()
+		{
+			return DigestLength;
+		}
+
+		public int GetByteLength()
+		{
+			return MyByteLength;
+		}
+
+		private void ProcessWord(
+            byte[]  b,
+            int     off)
+        {
+            x[xOff++] =   ((long)(b[off + 7] & 0xff) << 56)
+                        | ((long)(b[off + 6] & 0xff) << 48)
+                        | ((long)(b[off + 5] & 0xff) << 40)
+                        | ((long)(b[off + 4] & 0xff) << 32)
+                        | ((long)(b[off + 3] & 0xff) << 24)
+                        | ((long)(b[off + 2] & 0xff) << 16)
+                        | ((long)(b[off + 1] & 0xff) << 8)
+                        | ((uint)(b[off + 0] & 0xff));
+
+            if (xOff == x.Length)
+            {
+                ProcessBlock();
+            }
+
+            bOff = 0;
+        }
+
+        public void Update(
+            byte input)
+        {
+            Buffer[bOff++] = input;
+
+            if (bOff == Buffer.Length)
+            {
+                ProcessWord(Buffer, 0);
+            }
+
+            byteCount++;
+        }
+
+        public void BlockUpdate(
+            byte[]  input,
+            int     inOff,
+            int     length)
+        {
+            //
+            // fill the current word
+            //
+            while ((bOff != 0) && (length > 0))
+            {
+                Update(input[inOff]);
+
+                inOff++;
+                length--;
+            }
+
+            //
+            // process whole words.
+            //
+            while (length > 8)
+            {
+                ProcessWord(input, inOff);
+
+                inOff += 8;
+                length -= 8;
+                byteCount += 8;
+            }
+
+            //
+            // load in the remainder.
+            //
+            while (length > 0)
+            {
+                Update(input[inOff]);
+
+                inOff++;
+                length--;
+            }
+        }
+
+        private void RoundABC(
+            long    x,
+            long    mul)
+        {
+            c ^= x ;
+            a -= t1[(int)c & 0xff] ^ t2[(int)(c >> 16) & 0xff]
+                    ^ t3[(int)(c >> 32) & 0xff] ^ t4[(int)(c >> 48) & 0xff];
+            b += t4[(int)(c >> 8) & 0xff] ^ t3[(int)(c >> 24) & 0xff]
+                    ^ t2[(int)(c >> 40) & 0xff] ^ t1[(int)(c >> 56) & 0xff];
+            b *= mul;
+        }
+
+        private void RoundBCA(
+            long    x,
+            long    mul)
+        {
+            a ^= x ;
+            b -= t1[(int)a & 0xff] ^ t2[(int)(a >> 16) & 0xff]
+                    ^ t3[(int)(a >> 32) & 0xff] ^ t4[(int)(a >> 48) & 0xff];
+            c += t4[(int)(a >> 8) & 0xff] ^ t3[(int)(a >> 24) & 0xff]
+                    ^ t2[(int)(a >> 40) & 0xff] ^ t1[(int)(a >> 56) & 0xff];
+            c *= mul;
+        }
+
+        private void RoundCAB(
+            long    x,
+            long    mul)
+        {
+            b ^= x ;
+            c -= t1[(int)b & 0xff] ^ t2[(int)(b >> 16) & 0xff]
+                    ^ t3[(int)(b >> 32) & 0xff] ^ t4[(int)(b >> 48) & 0xff];
+            a += t4[(int)(b >> 8) & 0xff] ^ t3[(int)(b >> 24) & 0xff]
+                    ^ t2[(int)(b >> 40) & 0xff] ^ t1[(int)(b >> 56) & 0xff];
+            a *= mul;
+        }
+
+        private void KeySchedule()
+        {
+            x[0] -= x[7] ^ unchecked ((long) 0xA5A5A5A5A5A5A5A5L);
+            x[1] ^= x[0];
+            x[2] += x[1];
+            x[3] -= x[2] ^ ((~x[1]) << 19);
+            x[4] ^= x[3];
+            x[5] += x[4];
+            x[6] -= x[5] ^ (long) ((ulong) (~x[4]) >> 23);
+            x[7] ^= x[6];
+            x[0] += x[7];
+            x[1] -= x[0] ^ ((~x[7]) << 19);
+            x[2] ^= x[1];
+            x[3] += x[2];
+            x[4] -= x[3] ^ (long) ((ulong) (~x[2]) >> 23);
+            x[5] ^= x[4];
+            x[6] += x[5];
+            x[7] -= x[6] ^ 0x0123456789ABCDEFL;
+        }
+
+        private void ProcessBlock()
+        {
+            //
+            // save abc
+            //
+            long aa = a;
+            long bb = b;
+            long cc = c;
+
+            //
+            // rounds and schedule
+            //
+            RoundABC(x[0], 5);
+            RoundBCA(x[1], 5);
+            RoundCAB(x[2], 5);
+            RoundABC(x[3], 5);
+            RoundBCA(x[4], 5);
+            RoundCAB(x[5], 5);
+            RoundABC(x[6], 5);
+            RoundBCA(x[7], 5);
+
+            KeySchedule();
+
+            RoundCAB(x[0], 7);
+            RoundABC(x[1], 7);
+            RoundBCA(x[2], 7);
+            RoundCAB(x[3], 7);
+            RoundABC(x[4], 7);
+            RoundBCA(x[5], 7);
+            RoundCAB(x[6], 7);
+            RoundABC(x[7], 7);
+
+            KeySchedule();
+
+            RoundBCA(x[0], 9);
+            RoundCAB(x[1], 9);
+            RoundABC(x[2], 9);
+            RoundBCA(x[3], 9);
+            RoundCAB(x[4], 9);
+            RoundABC(x[5], 9);
+            RoundBCA(x[6], 9);
+            RoundCAB(x[7], 9);
+
+            //
+            // feed forward
+            //
+            a ^= aa;
+            b -= bb;
+            c += cc;
+
+            //
+            // clear the x buffer
+            //
+            xOff = 0;
+            for (int i = 0; i != x.Length; i++)
+            {
+                x[i] = 0;
+            }
+        }
+
+        private void UnpackWord(
+            long    r,
+            byte[]  output,
+            int     outOff)
+        {
+            output[outOff + 7]     = (byte)(r >> 56);
+            output[outOff + 6] = (byte)(r >> 48);
+            output[outOff + 5] = (byte)(r >> 40);
+            output[outOff + 4] = (byte)(r >> 32);
+            output[outOff + 3] = (byte)(r >> 24);
+            output[outOff + 2] = (byte)(r >> 16);
+            output[outOff + 1] = (byte)(r >> 8);
+            output[outOff] = (byte)r;
+        }
+
+        private void ProcessLength(
+            long    bitLength)
+        {
+            x[7] = bitLength;
+        }
+
+        private void Finish()
+        {
+            long    bitLength = (byteCount << 3);
+
+            Update((byte)0x01);
+
+            while (bOff != 0)
+            {
+                Update((byte)0);
+            }
+
+            ProcessLength(bitLength);
+
+            ProcessBlock();
+        }
+
+        public int DoFinal(
+            byte[]  output,
+            int     outOff)
+        {
+            Finish();
+
+            UnpackWord(a, output, outOff);
+            UnpackWord(b, output, outOff + 8);
+            UnpackWord(c, output, outOff + 16);
+
+            Reset();
+
+            return DigestLength;
+        }
+
+        /**
+        * reset the chaining variables
+        */
+        public void Reset()
+        {
+            a = unchecked((long) 0x0123456789ABCDEFL);
+            b = unchecked((long) 0xFEDCBA9876543210L);
+            c = unchecked((long) 0xF096A5B4C3B2E187L);
+
+            xOff = 0;
+            for (int i = 0; i != x.Length; i++)
+            {
+                x[i] = 0;
+            }
+
+            bOff = 0;
+            for (int i = 0; i != Buffer.Length; i++)
+            {
+                Buffer[i] = 0;
+            }
+
+            byteCount = 0;
+        }
+    }
+}
diff --git a/Crypto/src/crypto/digests/WhirlpoolDigest.cs b/Crypto/src/crypto/digests/WhirlpoolDigest.cs
new file mode 100644
index 000000000..df83f4508
--- /dev/null
+++ b/Crypto/src/crypto/digests/WhirlpoolDigest.cs
@@ -0,0 +1,397 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+	/**
+	* Implementation of WhirlpoolDigest, based on Java source published by Barreto
+	* and Rijmen.
+	*
+	*/
+	public sealed class WhirlpoolDigest : IDigest
+	{
+		private const int BYTE_LENGTH = 64;
+
+		private const int DIGEST_LENGTH_BYTES = 512 / 8;
+		private const int ROUNDS = 10;
+		private const int REDUCTION_POLYNOMIAL = 0x011d; // 2^8 + 2^4 + 2^3 + 2 + 1;
+
+		private static readonly int[] SBOX =
+		{
+			0x18, 0x23, 0xc6, 0xe8, 0x87, 0xb8, 0x01, 0x4f, 0x36, 0xa6, 0xd2, 0xf5, 0x79, 0x6f, 0x91, 0x52,
+			0x60, 0xbc, 0x9b, 0x8e, 0xa3, 0x0c, 0x7b, 0x35, 0x1d, 0xe0, 0xd7, 0xc2, 0x2e, 0x4b, 0xfe, 0x57,
+			0x15, 0x77, 0x37, 0xe5, 0x9f, 0xf0, 0x4a, 0xda, 0x58, 0xc9, 0x29, 0x0a, 0xb1, 0xa0, 0x6b, 0x85,
+			0xbd, 0x5d, 0x10, 0xf4, 0xcb, 0x3e, 0x05, 0x67, 0xe4, 0x27, 0x41, 0x8b, 0xa7, 0x7d, 0x95, 0xd8,
+			0xfb, 0xee, 0x7c, 0x66, 0xdd, 0x17, 0x47, 0x9e, 0xca, 0x2d, 0xbf, 0x07, 0xad, 0x5a, 0x83, 0x33,
+			0x63, 0x02, 0xaa, 0x71, 0xc8, 0x19, 0x49, 0xd9, 0xf2, 0xe3, 0x5b, 0x88, 0x9a, 0x26, 0x32, 0xb0,
+			0xe9, 0x0f, 0xd5, 0x80, 0xbe, 0xcd, 0x34, 0x48, 0xff, 0x7a, 0x90, 0x5f, 0x20, 0x68, 0x1a, 0xae,
+			0xb4, 0x54, 0x93, 0x22, 0x64, 0xf1, 0x73, 0x12, 0x40, 0x08, 0xc3, 0xec, 0xdb, 0xa1, 0x8d, 0x3d,
+			0x97, 0x00, 0xcf, 0x2b, 0x76, 0x82, 0xd6, 0x1b, 0xb5, 0xaf, 0x6a, 0x50, 0x45, 0xf3, 0x30, 0xef,
+			0x3f, 0x55, 0xa2, 0xea, 0x65, 0xba, 0x2f, 0xc0, 0xde, 0x1c, 0xfd, 0x4d, 0x92, 0x75, 0x06, 0x8a,
+			0xb2, 0xe6, 0x0e, 0x1f, 0x62, 0xd4, 0xa8, 0x96, 0xf9, 0xc5, 0x25, 0x59, 0x84, 0x72, 0x39, 0x4c,
+			0x5e, 0x78, 0x38, 0x8c, 0xd1, 0xa5, 0xe2, 0x61, 0xb3, 0x21, 0x9c, 0x1e, 0x43, 0xc7, 0xfc, 0x04,
+			0x51, 0x99, 0x6d, 0x0d, 0xfa, 0xdf, 0x7e, 0x24, 0x3b, 0xab, 0xce, 0x11, 0x8f, 0x4e, 0xb7, 0xeb,
+			0x3c, 0x81, 0x94, 0xf7, 0xb9, 0x13, 0x2c, 0xd3, 0xe7, 0x6e, 0xc4, 0x03, 0x56, 0x44, 0x7f, 0xa9,
+			0x2a, 0xbb, 0xc1, 0x53, 0xdc, 0x0b, 0x9d, 0x6c, 0x31, 0x74, 0xf6, 0x46, 0xac, 0x89, 0x14, 0xe1,
+			0x16, 0x3a, 0x69, 0x09, 0x70, 0xb6, 0xd0, 0xed, 0xcc, 0x42, 0x98, 0xa4, 0x28, 0x5c, 0xf8, 0x86
+		};
+
+		private static readonly long[] C0 = new long[256];
+		private static readonly long[] C1 = new long[256];
+		private static readonly long[] C2 = new long[256];
+		private static readonly long[] C3 = new long[256];
+		private static readonly long[] C4 = new long[256];
+		private static readonly long[] C5 = new long[256];
+		private static readonly long[] C6 = new long[256];
+		private static readonly long[] C7 = new long[256];
+
+		private readonly long[] _rc = new long[ROUNDS + 1];
+
+		/*
+			* increment() can be implemented in this way using 2 arrays or
+			* by having some temporary variables that are used to set the
+			* value provided by EIGHT[i] and carry within the loop.
+			*
+			* not having done any timing, this seems likely to be faster
+			* at the slight expense of 32*(sizeof short) bytes
+			*/
+		private static readonly short[] EIGHT = new short[BITCOUNT_ARRAY_SIZE];
+
+		static WhirlpoolDigest()
+		{
+			EIGHT[BITCOUNT_ARRAY_SIZE - 1] = 8;
+
+			for (int i = 0; i < 256; i++)
+			{
+				int v1 = SBOX[i];
+				int v2 = maskWithReductionPolynomial(v1 << 1);
+				int v4 = maskWithReductionPolynomial(v2 << 1);
+				int v5 = v4 ^ v1;
+				int v8 = maskWithReductionPolynomial(v4 << 1);
+				int v9 = v8 ^ v1;
+
+				C0[i] = packIntoLong(v1, v1, v4, v1, v8, v5, v2, v9);
+				C1[i] = packIntoLong(v9, v1, v1, v4, v1, v8, v5, v2);
+				C2[i] = packIntoLong(v2, v9, v1, v1, v4, v1, v8, v5);
+				C3[i] = packIntoLong(v5, v2, v9, v1, v1, v4, v1, v8);
+				C4[i] = packIntoLong(v8, v5, v2, v9, v1, v1, v4, v1);
+				C5[i] = packIntoLong(v1, v8, v5, v2, v9, v1, v1, v4);
+				C6[i] = packIntoLong(v4, v1, v8, v5, v2, v9, v1, v1);
+				C7[i] = packIntoLong(v1, v4, v1, v8, v5, v2, v9, v1);
+			}
+		}
+
+		public WhirlpoolDigest()
+		{
+			_rc[0] = 0L;
+			for (int r = 1; r <= ROUNDS; r++)
+			{
+				int i = 8 * (r - 1);
+				_rc[r] = (long)((ulong)C0[i] & 0xff00000000000000L) ^
+					(C1[i + 1] & (long) 0x00ff000000000000L) ^
+					(C2[i + 2] & (long) 0x0000ff0000000000L) ^
+					(C3[i + 3] & (long) 0x000000ff00000000L) ^
+					(C4[i + 4] & (long) 0x00000000ff000000L) ^
+					(C5[i + 5] & (long) 0x0000000000ff0000L) ^
+					(C6[i + 6] & (long) 0x000000000000ff00L) ^
+					(C7[i + 7] & (long) 0x00000000000000ffL);
+			}
+		}
+
+		private static long packIntoLong(int b7, int b6, int b5, int b4, int b3, int b2, int b1, int b0)
+		{
+			return
+				((long)b7 << 56) ^
+				((long)b6 << 48) ^
+				((long)b5 << 40) ^
+				((long)b4 << 32) ^
+				((long)b3 << 24) ^
+				((long)b2 << 16) ^
+				((long)b1 <<  8) ^
+				b0;
+		}
+
+		/*
+			* int's are used to prevent sign extension.  The values that are really being used are
+			* actually just 0..255
+			*/
+		private static int maskWithReductionPolynomial(int input)
+		{
+			int rv = input;
+			if (rv >= 0x100L) // high bit set
+			{
+				rv ^= REDUCTION_POLYNOMIAL; // reduced by the polynomial
+			}
+			return rv;
+		}
+
+		// --------------------------------------------------------------------------------------//
+
+		// -- buffer information --
+		private const int BITCOUNT_ARRAY_SIZE = 32;
+		private byte[]  _buffer    = new byte[64];
+		private int     _bufferPos;
+		private short[] _bitCount  = new short[BITCOUNT_ARRAY_SIZE];
+
+		// -- internal hash state --
+		private long[] _hash  = new long[8];
+		private long[] _K = new long[8]; // the round key
+		private long[] _L = new long[8];
+		private long[] _block = new long[8]; // mu (buffer)
+		private long[] _state = new long[8]; // the current "cipher" state
+
+
+
+		/**
+			* Copy constructor. This will copy the state of the provided message
+			* digest.
+			*/
+		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);
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Whirlpool"; }
+		}
+
+		public int GetDigestSize()
+		{
+			return DIGEST_LENGTH_BYTES;
+		}
+
+		public int DoFinal(byte[] output, int outOff)
+		{
+			// sets output[outOff] .. output[outOff+DIGEST_LENGTH_BYTES]
+			finish();
+
+			for (int i = 0; i < 8; i++)
+			{
+				convertLongToByteArray(_hash[i], output, outOff + (i * 8));
+			}
+
+			Reset();
+
+			return GetDigestSize();
+		}
+
+		/**
+			* Reset the chaining variables
+			*/
+		public void Reset()
+		{
+			// set variables to null, blank, whatever
+			_bufferPos = 0;
+			Array.Clear(_bitCount, 0, _bitCount.Length);
+			Array.Clear(_buffer, 0, _buffer.Length);
+			Array.Clear(_hash, 0, _hash.Length);
+			Array.Clear(_K, 0, _K.Length);
+			Array.Clear(_L, 0, _L.Length);
+			Array.Clear(_block, 0, _block.Length);
+			Array.Clear(_state, 0, _state.Length);
+		}
+
+		// this takes a buffer of information and fills the block
+		private void processFilledBuffer()
+		{
+			// copies into the block...
+			for (int i = 0; i < _state.Length; i++)
+			{
+				_block[i] = bytesToLongFromBuffer(_buffer, i * 8);
+			}
+			processBlock();
+			_bufferPos = 0;
+			Array.Clear(_buffer, 0, _buffer.Length);
+		}
+
+		private static long bytesToLongFromBuffer(byte[] buffer, int startPos)
+		{
+			long rv = (((buffer[startPos + 0] & 0xffL) << 56) |
+				((buffer[startPos + 1] & 0xffL) << 48) |
+				((buffer[startPos + 2] & 0xffL) << 40) |
+				((buffer[startPos + 3] & 0xffL) << 32) |
+				((buffer[startPos + 4] & 0xffL) << 24) |
+				((buffer[startPos + 5] & 0xffL) << 16) |
+				((buffer[startPos + 6] & 0xffL) <<  8) |
+				((buffer[startPos + 7]) & 0xffL));
+
+			return rv;
+		}
+
+		private static void convertLongToByteArray(long inputLong, byte[] outputArray, int offSet)
+		{
+			for (int i = 0; i < 8; i++)
+			{
+				outputArray[offSet + i] = (byte)((inputLong >> (56 - (i * 8))) & 0xff);
+			}
+		}
+
+		private void processBlock()
+		{
+			// buffer contents have been transferred to the _block[] array via
+			// processFilledBuffer
+
+			// compute and apply K^0
+			for (int i = 0; i < 8; i++)
+			{
+				_state[i] = _block[i] ^ (_K[i] = _hash[i]);
+			}
+
+			// iterate over the rounds
+			for (int round = 1; round <= ROUNDS; round++)
+			{
+				for (int i = 0; i < 8; i++)
+				{
+					_L[i] = 0;
+					_L[i] ^= C0[(int)(_K[(i - 0) & 7] >> 56) & 0xff];
+					_L[i] ^= C1[(int)(_K[(i - 1) & 7] >> 48) & 0xff];
+					_L[i] ^= C2[(int)(_K[(i - 2) & 7] >> 40) & 0xff];
+					_L[i] ^= C3[(int)(_K[(i - 3) & 7] >> 32) & 0xff];
+					_L[i] ^= C4[(int)(_K[(i - 4) & 7] >> 24) & 0xff];
+					_L[i] ^= C5[(int)(_K[(i - 5) & 7] >> 16) & 0xff];
+					_L[i] ^= C6[(int)(_K[(i - 6) & 7] >>  8) & 0xff];
+					_L[i] ^= C7[(int)(_K[(i - 7) & 7]) & 0xff];
+				}
+
+				Array.Copy(_L, 0, _K, 0, _K.Length);
+
+				_K[0] ^= _rc[round];
+
+				// apply the round transformation
+				for (int i = 0; i < 8; i++)
+				{
+					_L[i] = _K[i];
+
+					_L[i] ^= C0[(int)(_state[(i - 0) & 7] >> 56) & 0xff];
+					_L[i] ^= C1[(int)(_state[(i - 1) & 7] >> 48) & 0xff];
+					_L[i] ^= C2[(int)(_state[(i - 2) & 7] >> 40) & 0xff];
+					_L[i] ^= C3[(int)(_state[(i - 3) & 7] >> 32) & 0xff];
+					_L[i] ^= C4[(int)(_state[(i - 4) & 7] >> 24) & 0xff];
+					_L[i] ^= C5[(int)(_state[(i - 5) & 7] >> 16) & 0xff];
+					_L[i] ^= C6[(int)(_state[(i - 6) & 7] >> 8) & 0xff];
+					_L[i] ^= C7[(int)(_state[(i - 7) & 7]) & 0xff];
+				}
+
+				// save the current state
+				Array.Copy(_L, 0, _state, 0, _state.Length);
+			}
+
+			// apply Miuaguchi-Preneel compression
+			for (int i = 0; i < 8; i++)
+			{
+				_hash[i] ^= _state[i] ^ _block[i];
+			}
+
+		}
+
+		public void Update(byte input)
+		{
+			_buffer[_bufferPos] = input;
+
+			//Console.WriteLine("adding to buffer = "+_buffer[_bufferPos]);
+
+			++_bufferPos;
+
+			if (_bufferPos == _buffer.Length)
+			{
+				processFilledBuffer();
+			}
+
+			increment();
+		}
+
+		private void increment()
+		{
+			int carry = 0;
+			for (int i = _bitCount.Length - 1; i >= 0; i--)
+			{
+				int sum = (_bitCount[i] & 0xff) + EIGHT[i] + carry;
+
+				carry = sum >> 8;
+				_bitCount[i] = (short)(sum & 0xff);
+			}
+		}
+
+		public void BlockUpdate(byte[] input, int inOff, int length)
+		{
+			while (length > 0)
+			{
+				Update(input[inOff]);
+				++inOff;
+				--length;
+			}
+
+		}
+
+		private void finish()
+		{
+			/*
+				* this makes a copy of the current bit length. at the expense of an
+				* object creation of 32 bytes rather than providing a _stopCounting
+				* boolean which was the alternative I could think of.
+				*/
+			byte[] bitLength = copyBitLength();
+
+			_buffer[_bufferPos++] |= 0x80;
+
+			if (_bufferPos == _buffer.Length)
+			{
+				processFilledBuffer();
+			}
+
+			/*
+				* Final block contains
+				* [ ... data .... ][0][0][0][ length ]
+				*
+				* if [ length ] cannot fit.  Need to create a new block.
+				*/
+			if (_bufferPos > 32)
+			{
+				while (_bufferPos != 0)
+				{
+					Update((byte)0);
+				}
+			}
+
+			while (_bufferPos <= 32)
+			{
+				Update((byte)0);
+			}
+
+			// copy the length information to the final 32 bytes of the
+			// 64 byte block....
+			Array.Copy(bitLength, 0, _buffer, 32, bitLength.Length);
+
+			processFilledBuffer();
+		}
+
+		private byte[] copyBitLength()
+		{
+			byte[] rv = new byte[BITCOUNT_ARRAY_SIZE];
+			for (int i = 0; i < rv.Length; i++)
+			{
+				rv[i] = (byte)(_bitCount[i] & 0xff);
+			}
+			return rv;
+		}
+
+		public int GetByteLength()
+		{
+			return BYTE_LENGTH;
+		}
+	}
+}
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
new file mode 100644
index 000000000..81561e7f5
--- /dev/null
+++ b/Crypto/src/crypto/encodings/OaepEncoding.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.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;
+		}
+	}
+}
+
diff --git a/Crypto/src/crypto/encodings/Pkcs1Encoding.cs b/Crypto/src/crypto/encodings/Pkcs1Encoding.cs
new file mode 100644
index 000000000..d2225a7d4
--- /dev/null
+++ b/Crypto/src/crypto/encodings/Pkcs1Encoding.cs
@@ -0,0 +1,232 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Security;
+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;
+		}
+	}
+
+}
diff --git a/Crypto/src/crypto/engines/AesEngine.cs b/Crypto/src/crypto/engines/AesEngine.cs
new file mode 100644
index 000000000..4211a9559
--- /dev/null
+++ b/Crypto/src/crypto/engines/AesEngine.cs
@@ -0,0 +1,525 @@
+using System;
+
+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];
+		}
+	}
+}
diff --git a/Crypto/src/crypto/engines/AesFastEngine.cs b/Crypto/src/crypto/engines/AesFastEngine.cs
new file mode 100644
index 000000000..603b5ce4d
--- /dev/null
+++ b/Crypto/src/crypto/engines/AesFastEngine.cs
@@ -0,0 +1,853 @@
+using System;
+
+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 fast version with 8Kbytes of static tables for round precomputation
+    * </p>
+    */
+    public class AesFastEngine
+		: 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[] 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));
+		}
+
+        /* 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
+
+            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
+
+            //
+            // copy the key into the round key array
+            //
+
+            int 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 AesFastEngine()
+        {
+        }
+
+        /**
+        * 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");
+            }
+
+            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)
+        {
+            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];
+            }
+
+            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];
+
+            // 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];
+		}
+
+        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];
+            }
+
+            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];
+
+            // 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];
+		}
+    }
+}
diff --git a/Crypto/src/crypto/engines/AesLightEngine.cs b/Crypto/src/crypto/engines/AesLightEngine.cs
new file mode 100644
index 000000000..2c495578d
--- /dev/null
+++ b/Crypto/src/crypto/engines/AesLightEngine.cs
@@ -0,0 +1,419 @@
+using System;
+
+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];
+		}
+	}
+}
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/DesEdeEngine.cs b/Crypto/src/crypto/engines/DesEdeEngine.cs
new file mode 100644
index 000000000..b319888e3
--- /dev/null
+++ b/Crypto/src/crypto/engines/DesEdeEngine.cs
@@ -0,0 +1,100 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/// <remarks>A class that provides a basic DESede (or Triple DES) engine.</remarks>
+    public class DesEdeEngine
+		: 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());
+			}
+
+			byte[] keyMaster = ((KeyParameter)parameters).GetKey();
+
+			this.forEncryption = forEncryption;
+
+			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);
+
+			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
+        {
+            get { return "DESede"; }
+        }
+
+		public override int GetBlockSize()
+        {
+            return BLOCK_SIZE;
+        }
+
+		public override int ProcessBlock(
+            byte[]	input,
+            int		inOff,
+            byte[]	output,
+            int		outOff)
+        {
+            if (workingKey1 == null)
+                throw new InvalidOperationException("DESede 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");
+
+			byte[] temp = new byte[BLOCK_SIZE];
+
+			if (forEncryption)
+            {
+                DesFunc(workingKey1, input, inOff, temp, 0);
+                DesFunc(workingKey2, temp, 0, temp, 0);
+                DesFunc(workingKey3, temp, 0, output, outOff);
+            }
+            else
+            {
+                DesFunc(workingKey3, input, inOff, temp, 0);
+                DesFunc(workingKey2, temp, 0, temp, 0);
+                DesFunc(workingKey1, temp, 0, output, outOff);
+            }
+
+			return BLOCK_SIZE;
+        }
+
+		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
new file mode 100644
index 000000000..17593d2c0
--- /dev/null
+++ b/Crypto/src/crypto/engines/GOST28147Engine.cs
@@ -0,0 +1,377 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* implementation of GOST 28147-89
+	*/
+	public class Gost28147Engine
+		: IBlockCipher
+	{
+		private const int  BlockSize = 8;
+		private int[] workingKey = null;
+		private bool forEncryption;
+
+		private byte[] S = Sbox_Default;
+
+		// these are the S-boxes given in Applied Cryptography 2nd Ed., p. 333
+		// This is default S-box!
+		private static readonly byte[] Sbox_Default = {
+			0x4,0xA,0x9,0x2,0xD,0x8,0x0,0xE,0x6,0xB,0x1,0xC,0x7,0xF,0x5,0x3,
+			0xE,0xB,0x4,0xC,0x6,0xD,0xF,0xA,0x2,0x3,0x8,0x1,0x0,0x7,0x5,0x9,
+			0x5,0x8,0x1,0xD,0xA,0x3,0x4,0x2,0xE,0xF,0xC,0x7,0x6,0x0,0x9,0xB,
+			0x7,0xD,0xA,0x1,0x0,0x8,0x9,0xF,0xE,0x4,0x6,0xC,0xB,0x2,0x5,0x3,
+			0x6,0xC,0x7,0x1,0x5,0xF,0xD,0x8,0x4,0xA,0x9,0xE,0x0,0x3,0xB,0x2,
+			0x4,0xB,0xA,0x0,0x7,0x2,0x1,0xD,0x3,0x6,0x8,0x5,0x9,0xC,0xF,0xE,
+			0xD,0xB,0x4,0x1,0x3,0xF,0x5,0x9,0x0,0xA,0xE,0x7,0x6,0x8,0x2,0xC,
+			0x1,0xF,0xD,0x0,0x5,0x7,0xA,0x4,0x9,0x2,0x3,0xE,0x6,0xB,0x8,0xC
+		};
+
+		/*
+		 * class content S-box parameters for encrypting
+		 * getting from, see: http://tools.ietf.org/id/draft-popov-cryptopro-cpalgs-01.txt
+		 *                    http://tools.ietf.org/id/draft-popov-cryptopro-cpalgs-02.txt
+		 */
+		private static readonly byte[] ESbox_Test = {
+			0x4,0x2,0xF,0x5,0x9,0x1,0x0,0x8,0xE,0x3,0xB,0xC,0xD,0x7,0xA,0x6,
+			0xC,0x9,0xF,0xE,0x8,0x1,0x3,0xA,0x2,0x7,0x4,0xD,0x6,0x0,0xB,0x5,
+			0xD,0x8,0xE,0xC,0x7,0x3,0x9,0xA,0x1,0x5,0x2,0x4,0x6,0xF,0x0,0xB,
+			0xE,0x9,0xB,0x2,0x5,0xF,0x7,0x1,0x0,0xD,0xC,0x6,0xA,0x4,0x3,0x8,
+			0x3,0xE,0x5,0x9,0x6,0x8,0x0,0xD,0xA,0xB,0x7,0xC,0x2,0x1,0xF,0x4,
+			0x8,0xF,0x6,0xB,0x1,0x9,0xC,0x5,0xD,0x3,0x7,0xA,0x0,0xE,0x2,0x4,
+			0x9,0xB,0xC,0x0,0x3,0x6,0x7,0x5,0x4,0x8,0xE,0xF,0x1,0xA,0x2,0xD,
+			0xC,0x6,0x5,0x2,0xB,0x0,0x9,0xD,0x3,0xE,0x7,0xA,0xF,0x4,0x1,0x8
+		};
+
+		private static readonly byte[] ESbox_A = {
+			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
+		};
+
+		private static readonly byte[] ESbox_B = {
+			0x8,0x4,0xB,0x1,0x3,0x5,0x0,0x9,0x2,0xE,0xA,0xC,0xD,0x6,0x7,0xF,
+			0x0,0x1,0x2,0xA,0x4,0xD,0x5,0xC,0x9,0x7,0x3,0xF,0xB,0x8,0x6,0xE,
+			0xE,0xC,0x0,0xA,0x9,0x2,0xD,0xB,0x7,0x5,0x8,0xF,0x3,0x6,0x1,0x4,
+			0x7,0x5,0x0,0xD,0xB,0x6,0x1,0x2,0x3,0xA,0xC,0xF,0x4,0xE,0x9,0x8,
+			0x2,0x7,0xC,0xF,0x9,0x5,0xA,0xB,0x1,0x4,0x0,0xD,0x6,0x8,0xE,0x3,
+			0x8,0x3,0x2,0x6,0x4,0xD,0xE,0xB,0xC,0x1,0x7,0xF,0xA,0x0,0x9,0x5,
+			0x5,0x2,0xA,0xB,0x9,0x1,0xC,0x3,0x7,0x4,0xD,0x0,0x6,0xF,0x8,0xE,
+			0x0,0x4,0xB,0xE,0x8,0x3,0x7,0x1,0xA,0x2,0x9,0x6,0xF,0xD,0x5,0xC
+		};
+
+		private static readonly byte[] ESbox_C = {
+			0x1,0xB,0xC,0x2,0x9,0xD,0x0,0xF,0x4,0x5,0x8,0xE,0xA,0x7,0x6,0x3,
+			0x0,0x1,0x7,0xD,0xB,0x4,0x5,0x2,0x8,0xE,0xF,0xC,0x9,0xA,0x6,0x3,
+			0x8,0x2,0x5,0x0,0x4,0x9,0xF,0xA,0x3,0x7,0xC,0xD,0x6,0xE,0x1,0xB,
+			0x3,0x6,0x0,0x1,0x5,0xD,0xA,0x8,0xB,0x2,0x9,0x7,0xE,0xF,0xC,0x4,
+			0x8,0xD,0xB,0x0,0x4,0x5,0x1,0x2,0x9,0x3,0xC,0xE,0x6,0xF,0xA,0x7,
+			0xC,0x9,0xB,0x1,0x8,0xE,0x2,0x4,0x7,0x3,0x6,0x5,0xA,0x0,0xF,0xD,
+			0xA,0x9,0x6,0x8,0xD,0xE,0x2,0x0,0xF,0x3,0x5,0xB,0x4,0x1,0xC,0x7,
+			0x7,0x4,0x0,0x5,0xA,0x2,0xF,0xE,0xC,0x6,0x1,0xB,0xD,0x9,0x3,0x8
+		};
+
+		private static readonly byte[] ESbox_D = {
+			0xF,0xC,0x2,0xA,0x6,0x4,0x5,0x0,0x7,0x9,0xE,0xD,0x1,0xB,0x8,0x3,
+			0xB,0x6,0x3,0x4,0xC,0xF,0xE,0x2,0x7,0xD,0x8,0x0,0x5,0xA,0x9,0x1,
+			0x1,0xC,0xB,0x0,0xF,0xE,0x6,0x5,0xA,0xD,0x4,0x8,0x9,0x3,0x7,0x2,
+			0x1,0x5,0xE,0xC,0xA,0x7,0x0,0xD,0x6,0x2,0xB,0x4,0x9,0x3,0xF,0x8,
+			0x0,0xC,0x8,0x9,0xD,0x2,0xA,0xB,0x7,0x3,0x6,0x5,0x4,0xE,0xF,0x1,
+			0x8,0x0,0xF,0x3,0x2,0x5,0xE,0xB,0x1,0xA,0x4,0x7,0xC,0x9,0xD,0x6,
+			0x3,0x0,0x6,0xF,0x1,0xE,0x9,0x2,0xD,0x8,0xC,0x4,0xB,0xA,0x5,0x7,
+			0x1,0xA,0x6,0x8,0xF,0xB,0x0,0x4,0xC,0x3,0x5,0x9,0x7,0xD,0x2,0xE
+		};
+
+		//S-box for digest
+		private static readonly byte[] DSbox_Test = {
+			0x4,0xA,0x9,0x2,0xD,0x8,0x0,0xE,0x6,0xB,0x1,0xC,0x7,0xF,0x5,0x3,
+			0xE,0xB,0x4,0xC,0x6,0xD,0xF,0xA,0x2,0x3,0x8,0x1,0x0,0x7,0x5,0x9,
+			0x5,0x8,0x1,0xD,0xA,0x3,0x4,0x2,0xE,0xF,0xC,0x7,0x6,0x0,0x9,0xB,
+			0x7,0xD,0xA,0x1,0x0,0x8,0x9,0xF,0xE,0x4,0x6,0xC,0xB,0x2,0x5,0x3,
+			0x6,0xC,0x7,0x1,0x5,0xF,0xD,0x8,0x4,0xA,0x9,0xE,0x0,0x3,0xB,0x2,
+			0x4,0xB,0xA,0x0,0x7,0x2,0x1,0xD,0x3,0x6,0x8,0x5,0x9,0xC,0xF,0xE,
+			0xD,0xB,0x4,0x1,0x3,0xF,0x5,0x9,0x0,0xA,0xE,0x7,0x6,0x8,0x2,0xC,
+			0x1,0xF,0xD,0x0,0x5,0x7,0xA,0x4,0x9,0x2,0x3,0xE,0x6,0xB,0x8,0xC
+		};
+
+		private static readonly byte[] DSbox_A = {
+			0xA,0x4,0x5,0x6,0x8,0x1,0x3,0x7,0xD,0xC,0xE,0x0,0x9,0x2,0xB,0xF,
+			0x5,0xF,0x4,0x0,0x2,0xD,0xB,0x9,0x1,0x7,0x6,0x3,0xC,0xE,0xA,0x8,
+			0x7,0xF,0xC,0xE,0x9,0x4,0x1,0x0,0x3,0xB,0x5,0x2,0x6,0xA,0x8,0xD,
+			0x4,0xA,0x7,0xC,0x0,0xF,0x2,0x8,0xE,0x1,0x6,0x5,0xD,0xB,0x9,0x3,
+			0x7,0x6,0x4,0xB,0x9,0xC,0x2,0xA,0x1,0x8,0x0,0xE,0xF,0xD,0x3,0x5,
+			0x7,0x6,0x2,0x4,0xD,0x9,0xF,0x0,0xA,0x1,0x5,0xB,0x8,0xE,0xC,0x3,
+			0xD,0xE,0x4,0x1,0x7,0x0,0x5,0xA,0x3,0xC,0x8,0xF,0x6,0x2,0x9,0xB,
+			0x1,0x3,0xA,0x9,0x5,0xB,0x4,0xF,0x8,0x6,0x7,0xE,0xD,0x0,0x2,0xC
+		};
+
+		//
+		// pre-defined sbox table
+		//
+		private static readonly IDictionary sBoxes = Platform.CreateHashtable();
+
+		static Gost28147Engine()
+		{
+			AddSBox("Default", Sbox_Default);
+			AddSBox("E-TEST", ESbox_Test);
+			AddSBox("E-A", ESbox_A);
+			AddSBox("E-B", ESbox_B);
+			AddSBox("E-C", ESbox_C);
+			AddSBox("E-D", ESbox_D);
+			AddSBox("D-TEST", DSbox_Test);
+			AddSBox("D-A", DSbox_A);
+		}
+
+		private static void AddSBox(string sBoxName, byte[] sBox)
+		{
+			sBoxes.Add(sBoxName.ToUpperInvariant(), sBox);        
+		}
+
+		/**
+		* standard constructor.
+		*/
+		public Gost28147Engine()
+		{
+		}
+
+		/**
+		* initialise an Gost28147 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 ParametersWithSBox)
+			{
+				ParametersWithSBox   param = (ParametersWithSBox)parameters;
+
+				//
+				// Set the S-Box
+				//
+				byte[] sBox = param.GetSBox();
+				if (sBox.Length != Sbox_Default.Length)
+					throw new ArgumentException("invalid S-box passed to GOST28147 init");
+
+				this.S = Arrays.Clone(sBox);
+
+				//
+				// set key if there is one
+				//
+				if (param.Parameters != null)
+				{
+					workingKey = generateWorkingKey(forEncryption,
+							((KeyParameter)param.Parameters).GetKey());
+				}
+			}
+			else if (parameters is KeyParameter)
+			{
+				workingKey = generateWorkingKey(forEncryption,
+									((KeyParameter)parameters).GetKey());
+			}
+			else if (parameters != null)
+			{
+				throw new ArgumentException("invalid parameter passed to Gost28147 init - " + parameters.GetType().Name);
+			}
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Gost28147"; }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		public int GetBlockSize()
+		{
+			return BlockSize;
+		}
+
+		public int ProcessBlock(
+			byte[]	input,
+			int		inOff,
+			byte[]	output,
+			int		outOff)
+		{
+			if (workingKey == null)
+			{
+				throw new InvalidOperationException("Gost28147 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");
+			}
+
+			Gost28147Func(workingKey, input, inOff, output, outOff);
+
+			return BlockSize;
+		}
+
+		public void Reset()
+		{
+		}
+
+		private int[] generateWorkingKey(
+			bool forEncryption,
+			byte[]  userKey)
+		{
+			this.forEncryption = forEncryption;
+
+			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;
+		}
+
+		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 Gost28147Func(
+			int[]   workingKey,
+			byte[]  inBytes,
+			int     inOff,
+			byte[]  outBytes,
+			int     outOff)
+		{
+			int N1, N2, tmp;  //tmp -> for saving N1
+			N1 = bytesToint(inBytes, inOff);
+			N2 = bytesToint(inBytes, inOff + 4);
+
+			if (this.forEncryption)
+			{
+			for(int k = 0; k < 3; k++)  // 1-24 steps
+			{
+				for(int j = 0; j < 8; j++)
+				{
+					tmp = N1;
+					int step = Gost28147_mainStep(N1, workingKey[j]);
+					N1 = N2 ^ step; // CM2
+					N2 = tmp;
+				}
+			}
+			for(int j = 7; j > 0; j--)  // 25-31 steps
+			{
+				tmp = N1;
+				N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
+				N2 = tmp;
+			}
+			}
+			else //decrypt
+			{
+			for(int j = 0; j < 8; j++)  // 1-8 steps
+			{
+				tmp = N1;
+				N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
+				N2 = tmp;
+			}
+			for(int k = 0; k < 3; k++)  //9-31 steps
+			{
+				for(int j = 7; j >= 0; j--)
+				{
+					if ((k == 2) && (j==0))
+					{
+						break; // break 32 step
+					}
+					tmp = N1;
+					N1 = N2 ^ Gost28147_mainStep(N1, workingKey[j]); // CM2
+					N2 = tmp;
+				}
+			}
+			}
+
+			N2 = N2 ^ Gost28147_mainStep(N1, workingKey[0]);  // 32 step (N1=N1)
+
+			intTobytes(N1, outBytes, outOff);
+			intTobytes(N2, outBytes, outOff + 4);
+		}
+
+		//array of bytes to type int
+		private static int bytesToint(
+			byte[]  inBytes,
+			int     inOff)
+		{
+			return  (int)((inBytes[inOff + 3] << 24) & 0xff000000) + ((inBytes[inOff + 2] << 16) & 0xff0000) +
+					((inBytes[inOff + 1] << 8) & 0xff00) + (inBytes[inOff] & 0xff);
+		}
+
+		//int to array of bytes
+		private static void intTobytes(
+				int     num,
+				byte[]  outBytes,
+				int     outOff)
+		{
+				outBytes[outOff + 3] = (byte)(num >> 24);
+				outBytes[outOff + 2] = (byte)(num >> 16);
+				outBytes[outOff + 1] = (byte)(num >> 8);
+				outBytes[outOff] =     (byte)num;
+		}
+
+		/**
+		* Return the S-Box associated with SBoxName
+		* @param sBoxName name of the S-Box
+		* @return byte array representing the S-Box
+		*/
+		public static byte[] GetSBox(
+			string sBoxName)
+		{
+			byte[] sBox = (byte[])sBoxes[sBoxName.ToUpperInvariant()];
+
+			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\".");
+			}
+
+			return Arrays.Clone(sBox);
+		}
+	}
+}
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
new file mode 100644
index 000000000..1120a4104
--- /dev/null
+++ b/Crypto/src/crypto/engines/ISAACEngine.cs
@@ -0,0 +1,252 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/engines/IdeaEngine.cs b/Crypto/src/crypto/engines/IdeaEngine.cs
new file mode 100644
index 000000000..f763c5939
--- /dev/null
+++ b/Crypto/src/crypto/engines/IdeaEngine.cs
@@ -0,0 +1,341 @@
+#if INCLUDE_IDEA
+
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * A class that provides a basic International Data Encryption Algorithm (IDEA) engine.
+    * <p>
+    * 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>
+    * It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/
+	* </p>
+    * <p>
+	* 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>
+    */
+    public class IdeaEngine
+		: IBlockCipher
+    {
+        private const int  BLOCK_SIZE = 8;
+        private int[] workingKey;
+        /**
+        * standard constructor.
+        */
+        public IdeaEngine()
+        {
+        }
+        /**
+        * initialise an IDEA 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 IDEA init - " + parameters.GetType().ToString());
+
+			workingKey = GenerateWorkingKey(forEncryption,
+				((KeyParameter)parameters).GetKey());
+        }
+
+		public string AlgorithmName
+        {
+            get { return "IDEA"; }
+        }
+
+		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("IDEA 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");
+            }
+            IdeaFunc(workingKey, input, inOff, output, outOff);
+            return BLOCK_SIZE;
+        }
+        public void Reset()
+        {
+        }
+        private static readonly int    MASK = 0xffff;
+        private static readonly int    BASE = 0x10001;
+        private int BytesToWord(
+            byte[]  input,
+            int     inOff)
+        {
+            return ((input[inOff] << 8) & 0xff00) + (input[inOff + 1] & 0xff);
+        }
+        private void WordToBytes(
+            int     word,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            outBytes[outOff] = (byte)((uint) word >> 8);
+            outBytes[outOff + 1] = (byte)word;
+        }
+        /**
+        * return x = x * y where the multiplication is done modulo
+        * 65537 (0x10001) (as defined in the IDEA specification) and
+        * a zero input is taken to be 65536 (0x10000).
+        *
+        * @param x the x value
+        * @param y the y value
+        * @return x = x * y
+        */
+        private int Mul(
+            int x,
+            int y)
+        {
+            if (x == 0)
+            {
+                x = (BASE - y);
+            }
+            else if (y == 0)
+            {
+                x = (BASE - x);
+            }
+            else
+            {
+                int     p = x * y;
+                y = p & MASK;
+                x = (int) ((uint) p >> 16);
+                x = y - x + ((y < x) ? 1 : 0);
+            }
+            return x & MASK;
+        }
+        private void IdeaFunc(
+            int[]   workingKey,
+            byte[]  input,
+            int     inOff,
+            byte[]  outBytes,
+            int     outOff)
+        {
+            int     x0, x1, x2, x3, t0, t1;
+            int     keyOff = 0;
+            x0 = BytesToWord(input, inOff);
+            x1 = BytesToWord(input, inOff + 2);
+            x2 = BytesToWord(input, inOff + 4);
+            x3 = BytesToWord(input, inOff + 6);
+            for (int round = 0; round < 8; round++)
+            {
+                x0 = Mul(x0, workingKey[keyOff++]);
+                x1 += workingKey[keyOff++];
+                x1 &= MASK;
+                x2 += workingKey[keyOff++];
+                x2 &= MASK;
+                x3 = Mul(x3, workingKey[keyOff++]);
+                t0 = x1;
+                t1 = x2;
+                x2 ^= x0;
+                x1 ^= x3;
+                x2 = Mul(x2, workingKey[keyOff++]);
+                x1 += x2;
+                x1 &= MASK;
+                x1 = Mul(x1, workingKey[keyOff++]);
+                x2 += x1;
+                x2 &= MASK;
+                x0 ^= x1;
+                x3 ^= x2;
+                x1 ^= t1;
+                x2 ^= t0;
+            }
+            WordToBytes(Mul(x0, workingKey[keyOff++]), outBytes, outOff);
+            WordToBytes(x2 + workingKey[keyOff++], outBytes, outOff + 2);  /* NB: Order */
+            WordToBytes(x1 + workingKey[keyOff++], outBytes, outOff + 4);
+            WordToBytes(Mul(x3, workingKey[keyOff]), outBytes, outOff + 6);
+        }
+        /**
+        * The following function is used to expand the user key to the encryption
+        * subkey. The first 16 bytes are the user key, and the rest of the subkey
+        * is calculated by rotating the previous 16 bytes by 25 bits to the left,
+        * and so on until the subkey is completed.
+        */
+        private int[] ExpandKey(
+            byte[]  uKey)
+        {
+            int[]   key = new int[52];
+            if (uKey.Length < 16)
+            {
+                byte[]  tmp = new byte[16];
+                Array.Copy(uKey, 0, tmp, tmp.Length - uKey.Length, uKey.Length);
+                uKey = tmp;
+            }
+            for (int i = 0; i < 8; i++)
+            {
+                key[i] = BytesToWord(uKey, i * 2);
+            }
+            for (int i = 8; i < 52; i++)
+            {
+                if ((i & 7) < 6)
+                {
+                    key[i] = ((key[i - 7] & 127) << 9 | key[i - 6] >> 7) & MASK;
+                }
+                else if ((i & 7) == 6)
+                {
+                    key[i] = ((key[i - 7] & 127) << 9 | key[i - 14] >> 7) & MASK;
+                }
+                else
+                {
+                    key[i] = ((key[i - 15] & 127) << 9 | key[i - 14] >> 7) & MASK;
+                }
+            }
+            return key;
+        }
+        /**
+        * This function computes multiplicative inverse using Euclid's Greatest
+        * Common Divisor algorithm. Zero and one are self inverse.
+        * <p>
+        * i.e. x * MulInv(x) == 1 (modulo BASE)
+		* </p>
+        */
+        private int MulInv(
+            int x)
+        {
+            int t0, t1, q, y;
+
+            if (x < 2)
+            {
+                return x;
+            }
+            t0 = 1;
+            t1 = BASE / x;
+            y  = BASE % x;
+            while (y != 1)
+            {
+                q = x / y;
+                x = x % y;
+                t0 = (t0 + (t1 * q)) & MASK;
+                if (x == 1)
+                {
+                    return t0;
+                }
+                q = y / x;
+                y = y % x;
+                t1 = (t1 + (t0 * q)) & MASK;
+            }
+            return (1 - t1) & MASK;
+        }
+        /**
+        * Return the additive inverse of x.
+        * <p>
+        * i.e. x + AddInv(x) == 0
+		* </p>
+        */
+        int AddInv(
+            int x)
+        {
+            return (0 - x) & MASK;
+        }
+
+        /**
+        * The function to invert the encryption subkey to the decryption subkey.
+        * It also involves the multiplicative inverse and the additive inverse functions.
+        */
+        private int[] InvertKey(
+            int[] inKey)
+        {
+            int     t1, t2, t3, t4;
+            int     p = 52;                 /* We work backwards */
+            int[]   key = new int[52];
+            int     inOff = 0;
+
+            t1 = MulInv(inKey[inOff++]);
+            t2 = AddInv(inKey[inOff++]);
+            t3 = AddInv(inKey[inOff++]);
+            t4 = MulInv(inKey[inOff++]);
+            key[--p] = t4;
+            key[--p] = t3;
+            key[--p] = t2;
+            key[--p] = t1;
+
+            for (int round = 1; round < 8; round++)
+            {
+                t1 = inKey[inOff++];
+                t2 = inKey[inOff++];
+                key[--p] = t2;
+                key[--p] = t1;
+
+                t1 = MulInv(inKey[inOff++]);
+                t2 = AddInv(inKey[inOff++]);
+                t3 = AddInv(inKey[inOff++]);
+                t4 = MulInv(inKey[inOff++]);
+                key[--p] = t4;
+                key[--p] = t2; /* NB: Order */
+                key[--p] = t3;
+                key[--p] = t1;
+            }
+            t1 = inKey[inOff++];
+            t2 = inKey[inOff++];
+            key[--p] = t2;
+            key[--p] = t1;
+
+            t1 = MulInv(inKey[inOff++]);
+            t2 = AddInv(inKey[inOff++]);
+            t3 = AddInv(inKey[inOff++]);
+            t4 = MulInv(inKey[inOff]);
+            key[--p] = t4;
+            key[--p] = t3;
+            key[--p] = t2;
+            key[--p] = t1;
+            return key;
+        }
+
+        private int[] GenerateWorkingKey(
+            bool forEncryption,
+            byte[]  userKey)
+        {
+            if (forEncryption)
+            {
+                return ExpandKey(userKey);
+            }
+            else
+            {
+                return InvertKey(ExpandKey(userKey));
+            }
+        }
+    }
+}
+
+#endif
diff --git a/Crypto/src/crypto/engines/IesEngine.cs b/Crypto/src/crypto/engines/IesEngine.cs
new file mode 100644
index 000000000..c49b2a9ee
--- /dev/null
+++ b/Crypto/src/crypto/engines/IesEngine.cs
@@ -0,0 +1,236 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    /**
+    * support class for constructing intergrated encryption ciphers
+    * for doing basic message exchanges on top of key agreement ciphers
+    */
+    public class IesEngine
+    {
+        private readonly IBasicAgreement     agree;
+        private readonly IDerivationFunction kdf;
+        private readonly IMac                mac;
+        private readonly BufferedBlockCipher cipher;
+		private readonly byte[]              macBuf;
+
+		private bool				forEncryption;
+        private ICipherParameters	privParam, pubParam;
+        private IesParameters		param;
+
+        /**
+        * set up for use with stream mode, where the key derivation function
+        * is used to provide a stream of bytes to xor with the message.
+        *
+        * @param agree the key agreement used as the basis for the encryption
+        * @param kdf the key derivation function used for byte generation
+        * @param mac the message authentication code generator for the message
+        */
+        public IesEngine(
+            IBasicAgreement     agree,
+            IDerivationFunction kdf,
+            IMac                mac)
+        {
+            this.agree = agree;
+            this.kdf = kdf;
+            this.mac = mac;
+            this.macBuf = new byte[mac.GetMacSize()];
+//            this.cipher = null;
+        }
+
+        /**
+        * set up for use in conjunction with a block cipher to handle the
+        * message.
+        *
+        * @param agree the key agreement used as the basis for the encryption
+        * @param kdf the key derivation function used for byte generation
+        * @param mac the message authentication code generator for the message
+        * @param cipher the cipher to used for encrypting the message
+        */
+        public IesEngine(
+            IBasicAgreement     agree,
+            IDerivationFunction kdf,
+            IMac                mac,
+            BufferedBlockCipher cipher)
+        {
+            this.agree = agree;
+            this.kdf = kdf;
+            this.mac = mac;
+            this.macBuf = new byte[mac.GetMacSize()];
+            this.cipher = cipher;
+        }
+
+        /**
+        * Initialise the encryptor.
+        *
+        * @param forEncryption whether or not this is encryption/decryption.
+        * @param privParam our private key parameters
+        * @param pubParam the recipient's/sender's public key parameters
+        * @param param encoding and derivation parameters.
+        */
+        public void Init(
+            bool                     forEncryption,
+            ICipherParameters            privParameters,
+            ICipherParameters            pubParameters,
+            ICipherParameters            iesParameters)
+        {
+            this.forEncryption = forEncryption;
+            this.privParam = privParameters;
+            this.pubParam = pubParameters;
+            this.param = (IesParameters)iesParameters;
+        }
+
+        private byte[] DecryptBlock(
+            byte[]  in_enc,
+            int     inOff,
+            int     inLen,
+            byte[]  z)
+        {
+            byte[]          M = null;
+            KeyParameter    macKey = null;
+            KdfParameters   kParam = new KdfParameters(z, param.GetDerivationV());
+            int             macKeySize = param.MacKeySize;
+
+            kdf.Init(kParam);
+
+            inLen -= mac.GetMacSize();
+
+            if (cipher == null)     // stream mode
+            {
+				byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));
+
+                M = new byte[inLen];
+
+                for (int i = 0; i != inLen; i++)
+                {
+                    M[i] = (byte)(in_enc[inOff + i] ^ Buffer[i]);
+                }
+
+                macKey = new KeyParameter(Buffer, inLen, (macKeySize / 8));
+            }
+            else
+            {
+                int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize;
+				byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));
+
+                cipher.Init(false, new KeyParameter(Buffer, 0, (cipherKeySize / 8)));
+
+				M = cipher.DoFinal(in_enc, inOff, inLen);
+
+				macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
+            }
+
+            byte[] macIV = param.GetEncodingV();
+
+            mac.Init(macKey);
+            mac.BlockUpdate(in_enc, inOff, inLen);
+            mac.BlockUpdate(macIV, 0, macIV.Length);
+            mac.DoFinal(macBuf, 0);
+
+			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."));
+                }
+            }
+
+            return M;
+        }
+
+        private byte[] EncryptBlock(
+            byte[]  input,
+            int     inOff,
+            int     inLen,
+            byte[]  z)
+        {
+            byte[]          C = null;
+            KeyParameter    macKey = null;
+            KdfParameters   kParam = new KdfParameters(z, param.GetDerivationV());
+            int             c_text_length = 0;
+            int             macKeySize = param.MacKeySize;
+
+            if (cipher == null)     // stream mode
+            {
+				byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));
+
+                C = new byte[inLen + mac.GetMacSize()];
+                c_text_length = inLen;
+
+				for (int i = 0; i != inLen; i++)
+                {
+                    C[i] = (byte)(input[inOff + i] ^ Buffer[i]);
+                }
+
+                macKey = new KeyParameter(Buffer, inLen, (macKeySize / 8));
+            }
+            else
+            {
+                int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize;
+				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];
+
+				int len = cipher.ProcessBytes(input, inOff, inLen, tmp, 0);
+				len += cipher.DoFinal(tmp, len);
+
+				C = new byte[len + mac.GetMacSize()];
+				c_text_length = len;
+
+				Array.Copy(tmp, 0, C, 0, len);
+
+				macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
+            }
+
+            byte[] macIV = param.GetEncodingV();
+
+            mac.Init(macKey);
+            mac.BlockUpdate(C, 0, c_text_length);
+            mac.BlockUpdate(macIV, 0, macIV.Length);
+            //
+            // return the message and it's MAC
+            //
+            mac.DoFinal(C, c_text_length);
+            return C;
+        }
+
+		private byte[] GenerateKdfBytes(
+			KdfParameters	kParam,
+			int				length)
+		{
+			byte[] buf = new byte[length];
+
+			kdf.Init(kParam);
+
+			kdf.GenerateBytes(buf, 0, buf.Length);
+
+			return buf;
+		}
+
+		public byte[] ProcessBlock(
+            byte[]  input,
+            int     inOff,
+            int     inLen)
+        {
+            agree.Init(privParam);
+
+			BigInteger z = agree.CalculateAgreement(pubParam);
+
+			// TODO Is a fixed length result expected?
+			byte[] zBytes = z.ToByteArrayUnsigned();
+
+            return forEncryption
+				?	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
new file mode 100644
index 000000000..9a0d1e0fe
--- /dev/null
+++ b/Crypto/src/crypto/engines/NaccacheSternEngine.cs
@@ -0,0 +1,432 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	* NaccacheStern Engine. For details on this cipher, please see
+	* http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+	*/
+	public class NaccacheSternEngine
+		: IAsymmetricBlockCipher
+	{
+		private bool forEncryption;
+
+		private NaccacheSternKeyParameters key;
+
+		private IList[] lookup = null;
+
+		private bool debug = false;
+
+		public string AlgorithmName
+		{
+			get { return "NaccacheStern"; }
+		}
+
+		/**
+		* Initializes this algorithm. Must be called before all other Functions.
+		*
+		* @see org.bouncycastle.crypto.AsymmetricBlockCipher#init(bool,
+		*      org.bouncycastle.crypto.CipherParameters)
+		*/
+		public void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			this.forEncryption = forEncryption;
+
+			if (parameters is ParametersWithRandom)
+			{
+				parameters = ((ParametersWithRandom) parameters).Parameters;
+			}
+
+			key = (NaccacheSternKeyParameters)parameters;
+
+			// construct lookup table for faster decryption if necessary
+			if (!this.forEncryption)
+			{
+				if (debug)
+				{
+					System.Diagnostics.Debug.WriteLine("Constructing lookup Array");
+				}
+				NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
+				IList primes = priv.SmallPrimesList;
+				lookup = new IList[primes.Count];
+				for (int i = 0; i < primes.Count; i++)
+				{
+					BigInteger actualPrime = (BigInteger) primes[i];
+					int actualPrimeValue = actualPrime.IntValue;
+
+					lookup[i] = Platform.CreateArrayList(actualPrimeValue);
+					lookup[i].Add(BigInteger.One);
+
+					if (debug)
+					{
+                        System.Diagnostics.Debug.WriteLine("Constructing lookup ArrayList for " + actualPrimeValue);
+					}
+
+					BigInteger accJ = BigInteger.Zero;
+
+					for (int j = 1; j < actualPrimeValue; j++)
+					{
+//						BigInteger bigJ = BigInteger.ValueOf(j);
+//						accJ = priv.PhiN.Multiply(bigJ);
+						accJ = accJ.Add(priv.PhiN);
+						BigInteger comp = accJ.Divide(actualPrime);
+						lookup[i].Add(priv.G.ModPow(comp, priv.Modulus));
+					}
+				}
+			}
+		}
+
+		public bool Debug
+		{
+			set { this.debug = value; }
+		}
+
+		/**
+		* Returns the input block size of this algorithm.
+		*
+		* @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetInputBlockSize()
+		*/
+		public int GetInputBlockSize()
+		{
+			if (forEncryption)
+			{
+				// We can only encrypt values up to lowerSigmaBound
+				return (key.LowerSigmaBound + 7) / 8 - 1;
+			}
+			else
+			{
+				// We pad to modulus-size bytes for easier decryption.
+//				return key.Modulus.ToByteArray().Length;
+				return key.Modulus.BitLength / 8 + 1;
+			}
+		}
+
+		/**
+		* Returns the output block size of this algorithm.
+		*
+		* @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetOutputBlockSize()
+		*/
+		public int GetOutputBlockSize()
+		{
+			if (forEncryption)
+			{
+				// encrypted Data is always padded up to modulus size
+//				return key.Modulus.ToByteArray().Length;
+				return key.Modulus.BitLength / 8 + 1;
+			}
+			else
+			{
+				// decrypted Data has upper limit lowerSigmaBound
+				return (key.LowerSigmaBound + 7) / 8 - 1;
+			}
+		}
+
+		/**
+		* Process a single Block using the Naccache-Stern algorithm.
+		*
+		* @see org.bouncycastle.crypto.AsymmetricBlockCipher#ProcessBlock(byte[],
+		*      int, int)
+		*/
+		public byte[] ProcessBlock(
+			byte[]	inBytes,
+			int		inOff,
+			int		length)
+		{
+			if (key == null)
+				throw new InvalidOperationException("NaccacheStern engine not initialised");
+			if (length > (GetInputBlockSize() + 1))
+				throw new DataLengthException("input too large for Naccache-Stern cipher.\n");
+
+			if (!forEncryption)
+			{
+				// At decryption make sure that we receive padded data blocks
+				if (length < GetInputBlockSize())
+				{
+					throw new InvalidCipherTextException("BlockLength does not match modulus for Naccache-Stern cipher.\n");
+				}
+			}
+
+			// transform input into BigInteger
+			BigInteger input = new BigInteger(1, inBytes, inOff, length);
+
+			if (debug)
+			{
+                System.Diagnostics.Debug.WriteLine("input as BigInteger: " + input);
+			}
+
+			byte[] output;
+			if (forEncryption)
+			{
+				output = Encrypt(input);
+			}
+			else
+			{
+				IList plain = Platform.CreateArrayList();
+				NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
+				IList primes = priv.SmallPrimesList;
+				// Get Chinese Remainders of CipherText
+				for (int i = 0; i < primes.Count; i++)
+				{
+					BigInteger exp = input.ModPow(priv.PhiN.Divide((BigInteger)primes[i]), priv.Modulus);
+					IList al = lookup[i];
+					if (lookup[i].Count != ((BigInteger)primes[i]).IntValue)
+					{
+						if (debug)
+						{
+                            System.Diagnostics.Debug.WriteLine("Prime is " + primes[i] + ", lookup table has size " + al.Count);
+						}
+						throw new InvalidCipherTextException("Error in lookup Array for "
+										+ ((BigInteger)primes[i]).IntValue
+										+ ": Size mismatch. Expected ArrayList with length "
+										+ ((BigInteger)primes[i]).IntValue + " but found ArrayList of length "
+										+ lookup[i].Count);
+					}
+					int lookedup = al.IndexOf(exp);
+
+					if (lookedup == -1)
+					{
+						if (debug)
+						{
+                            System.Diagnostics.Debug.WriteLine("Actual prime is " + primes[i]);
+                            System.Diagnostics.Debug.WriteLine("Decrypted value is " + exp);
+
+                            System.Diagnostics.Debug.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]);
+							}
+						}
+						throw new InvalidCipherTextException("Lookup failed");
+					}
+					plain.Add(BigInteger.ValueOf(lookedup));
+				}
+				BigInteger test = chineseRemainder(plain, primes);
+
+				// Should not be used as an oracle, so reencrypt output to see
+				// if it corresponds to input
+
+				// this breaks probabilisic encryption, so disable it. Anyway, we do
+				// use the first n primes for key generation, so it is pretty easy
+				// to guess them. But as stated in the paper, this is not a security
+				// breach. So we can just work with the correct sigma.
+
+				// if (debug) {
+				//      Console.WriteLine("Decryption is " + test);
+				// }
+				// if ((key.G.ModPow(test, key.Modulus)).Equals(input)) {
+				//      output = test.ToByteArray();
+				// } else {
+				//      if(debug){
+				//          Console.WriteLine("Engine seems to be used as an oracle,
+				//          returning null");
+				//      }
+				//      output = null;
+				// }
+
+				output = test.ToByteArray();
+			}
+
+			return output;
+		}
+
+		/**
+		* Encrypts a BigInteger aka Plaintext with the public key.
+		*
+		* @param plain
+		*            The BigInteger to encrypt
+		* @return The byte[] representation of the encrypted BigInteger (i.e.
+		*         crypted.toByteArray())
+		*/
+		public byte[] Encrypt(
+			BigInteger plain)
+		{
+			// Always return modulus size values 0-padded at the beginning
+			// 0-padding at the beginning is correctly parsed by BigInteger :)
+//			byte[] output = key.Modulus.ToByteArray();
+//			Array.Clear(output, 0, output.Length);
+			byte[] output = new byte[key.Modulus.BitLength / 8 + 1];
+
+			byte[] tmp = key.G.ModPow(plain, key.Modulus).ToByteArray();
+			Array.Copy(tmp, 0, output, output.Length - tmp.Length, tmp.Length);
+			if (debug)
+			{
+                System.Diagnostics.Debug.WriteLine("Encrypted value is:  " + new BigInteger(output));
+			}
+			return output;
+		}
+
+		/**
+		* Adds the contents of two encrypted blocks mod sigma
+		*
+		* @param block1
+		*            the first encrypted block
+		* @param block2
+		*            the second encrypted block
+		* @return encrypt((block1 + block2) mod sigma)
+		* @throws InvalidCipherTextException
+		*/
+		public byte[] AddCryptedBlocks(
+			byte[] block1,
+			byte[] block2)
+		{
+			// check for correct blocksize
+			if (forEncryption)
+			{
+				if ((block1.Length > GetOutputBlockSize())
+						|| (block2.Length > GetOutputBlockSize()))
+				{
+					throw new InvalidCipherTextException(
+							"BlockLength too large for simple addition.\n");
+				}
+			}
+			else
+			{
+				if ((block1.Length > GetInputBlockSize())
+						|| (block2.Length > GetInputBlockSize()))
+				{
+					throw new InvalidCipherTextException(
+							"BlockLength too large for simple addition.\n");
+				}
+			}
+
+			// calculate resulting block
+			BigInteger m1Crypt = new BigInteger(1, block1);
+			BigInteger m2Crypt = new BigInteger(1, block2);
+			BigInteger m1m2Crypt = m1Crypt.Multiply(m2Crypt);
+			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);
+			}
+
+			//byte[] output = key.Modulus.ToByteArray();
+			//Array.Clear(output, 0, output.Length);
+			byte[] output = new byte[key.Modulus.BitLength / 8 + 1];
+
+			byte[] m1m2CryptBytes = m1m2Crypt.ToByteArray();
+			Array.Copy(m1m2CryptBytes, 0, output,
+				output.Length - m1m2CryptBytes.Length, m1m2CryptBytes.Length);
+
+			return output;
+		}
+
+		/**
+		* Convenience Method for data exchange with the cipher.
+		*
+		* Determines blocksize and splits data to blocksize.
+		*
+		* @param data the data to be processed
+		* @return the data after it went through the NaccacheSternEngine.
+		* @throws InvalidCipherTextException
+		*/
+		public byte[] ProcessData(
+			byte[] data)
+		{
+			if (debug)
+			{
+                System.Diagnostics.Debug.WriteLine("");
+			}
+			if (data.Length > GetInputBlockSize())
+			{
+				int inBlocksize = GetInputBlockSize();
+				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");
+				}
+				int datapos = 0;
+				int retpos = 0;
+				byte[] retval = new byte[(data.Length / inBlocksize + 1) * outBlocksize];
+				while (datapos < data.Length)
+				{
+					byte[] tmp;
+					if (datapos + inBlocksize < data.Length)
+					{
+						tmp = ProcessBlock(data, datapos, inBlocksize);
+						datapos += inBlocksize;
+					}
+					else
+					{
+						tmp = ProcessBlock(data, datapos, data.Length - datapos);
+						datapos += data.Length - datapos;
+					}
+					if (debug)
+					{
+                        System.Diagnostics.Debug.WriteLine("new datapos is " + datapos);
+					}
+					if (tmp != null)
+					{
+						tmp.CopyTo(retval, retpos);
+						retpos += tmp.Length;
+					}
+					else
+					{
+						if (debug)
+						{
+                            System.Diagnostics.Debug.WriteLine("cipher returned null");
+						}
+						throw new InvalidCipherTextException("cipher returned null");
+					}
+				}
+				byte[] ret = new byte[retpos];
+				Array.Copy(retval, 0, ret, 0, retpos);
+				if (debug)
+				{
+                    System.Diagnostics.Debug.WriteLine("returning " + ret.Length + " bytes");
+				}
+				return ret;
+			}
+			else
+			{
+				if (debug)
+				{
+                    System.Diagnostics.Debug.WriteLine("data size is less then input block size, processing directly");
+				}
+				return ProcessBlock(data, 0, data.Length);
+			}
+		}
+
+		/**
+		* Computes the integer x that is expressed through the given primes and the
+		* congruences with the chinese remainder theorem (CRT).
+		*
+		* @param congruences
+		*            the congruences c_i
+		* @param primes
+		*            the primes p_i
+		* @return an integer x for that x % p_i == c_i
+		*/
+		private static BigInteger chineseRemainder(IList congruences, IList primes)
+		{
+			BigInteger retval = BigInteger.Zero;
+			BigInteger all = BigInteger.One;
+			for (int i = 0; i < primes.Count; i++)
+			{
+				all = all.Multiply((BigInteger)primes[i]);
+			}
+			for (int i = 0; i < primes.Count; i++)
+			{
+				BigInteger a = (BigInteger)primes[i];
+				BigInteger b = all.Divide(a);
+				BigInteger b2 = b.ModInverse(a);
+				BigInteger tmp = b.Multiply(b2);
+				tmp = tmp.Multiply((BigInteger)congruences[i]);
+				retval = retval.Add(tmp);
+			}
+
+			return retval.Mod(all);
+		}
+	}
+}
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
new file mode 100644
index 000000000..7596e7218
--- /dev/null
+++ b/Crypto/src/crypto/engines/RFC3394WrapEngine.cs
@@ -0,0 +1,178 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/// <remarks>
+	/// An implementation of the AES Key Wrapper from the NIST Key Wrap
+	/// Specification as described in RFC 3394.
+	/// <p/>
+	/// For further details see: <a href="http://www.ietf.org/rfc/rfc3394.txt">http://www.ietf.org/rfc/rfc3394.txt</a>
+	/// and  <a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf">http://csrc.nist.gov/encryption/kms/key-wrap.pdf</a>.
+	/// </remarks>
+	public class Rfc3394WrapEngine
+		: IWrapper
+	{
+		private readonly IBlockCipher engine;
+
+		private KeyParameter	param;
+		private bool			forWrapping;
+
+		private byte[] iv =
+		{
+			0xa6, 0xa6, 0xa6, 0xa6,
+			0xa6, 0xa6, 0xa6, 0xa6
+		};
+
+		public Rfc3394WrapEngine(
+			IBlockCipher engine)
+		{
+			this.engine = engine;
+		}
+
+		public void Init(
+			bool				forWrapping,
+			ICipherParameters	parameters)
+		{
+			this.forWrapping = forWrapping;
+
+			if (parameters is ParametersWithRandom)
+			{
+				parameters = ((ParametersWithRandom) parameters).Parameters;
+			}
+
+			if (parameters is KeyParameter)
+			{
+				this.param = (KeyParameter) parameters;
+			}
+			else if (parameters is ParametersWithIV)
+			{
+				ParametersWithIV pIV = (ParametersWithIV) parameters;
+				byte[] iv = pIV.GetIV();
+
+				if (iv.Length != 8)
+					throw new ArgumentException("IV length not equal to 8", "parameters");
+
+				this.iv = iv;
+				this.param = (KeyParameter) pIV.Parameters;
+			}
+			else
+			{
+				// TODO Throw an exception for bad parameters?
+			}
+		}
+
+		public string AlgorithmName
+		{
+			get { return engine.AlgorithmName; }
+		}
+
+		public byte[] Wrap(
+			byte[]	input,
+			int		inOff,
+			int		inLen)
+		{
+			if (!forWrapping)
+			{
+				throw new InvalidOperationException("not set for wrapping");
+			}
+
+			int n = inLen / 8;
+
+			if ((n * 8) != inLen)
+			{
+				throw new DataLengthException("wrap data must be a multiple of 8 bytes");
+			}
+
+			byte[] block = new byte[inLen + iv.Length];
+			byte[] buf = new byte[8 + iv.Length];
+
+			Array.Copy(iv, 0, block, 0, iv.Length);
+			Array.Copy(input, 0, block, iv.Length, inLen);
+
+			engine.Init(true, param);
+
+			for (int j = 0; j != 6; j++)
+			{
+				for (int i = 1; i <= n; i++)
+				{
+					Array.Copy(block, 0, buf, 0, iv.Length);
+					Array.Copy(block, 8 * i, buf, iv.Length, 8);
+					engine.ProcessBlock(buf, 0, buf, 0);
+
+					int t = n * j + i;
+					for (int k = 1; t != 0; k++)
+					{
+						byte v = (byte)t;
+
+						buf[iv.Length - k] ^= v;
+						t = (int) ((uint)t >> 8);
+					}
+
+					Array.Copy(buf, 0, block, 0, 8);
+					Array.Copy(buf, 8, block, 8 * i, 8);
+				}
+			}
+
+			return block;
+		}
+
+		public byte[] Unwrap(
+			byte[]  input,
+			int     inOff,
+			int     inLen)
+		{
+			if (forWrapping)
+			{
+				throw new InvalidOperationException("not set for unwrapping");
+			}
+
+			int n = inLen / 8;
+
+			if ((n * 8) != inLen)
+			{
+				throw new InvalidCipherTextException("unwrap data must be a multiple of 8 bytes");
+			}
+
+			byte[]  block = new byte[inLen - iv.Length];
+			byte[]  a = new byte[iv.Length];
+			byte[]  buf = new byte[8 + iv.Length];
+
+			Array.Copy(input, 0, a, 0, iv.Length);
+			Array.Copy(input, iv.Length, block, 0, inLen - iv.Length);
+
+			engine.Init(false, param);
+
+			n = n - 1;
+
+			for (int j = 5; j >= 0; j--)
+			{
+				for (int i = n; i >= 1; i--)
+				{
+					Array.Copy(a, 0, buf, 0, iv.Length);
+					Array.Copy(block, 8 * (i - 1), buf, iv.Length, 8);
+
+					int t = n * j + i;
+					for (int k = 1; t != 0; k++)
+					{
+						byte v = (byte)t;
+
+						buf[iv.Length - k] ^= v;
+						t = (int) ((uint)t >> 8);
+					}
+
+					engine.ProcessBlock(buf, 0, buf, 0);
+					Array.Copy(buf, 0, a, 0, 8);
+					Array.Copy(buf, 8, block, 8 * (i - 1), 8);
+				}
+			}
+
+			if (!Arrays.ConstantTimeAreEqual(a, iv))
+				throw new InvalidCipherTextException("checksum failed");
+
+			return block;
+		}
+	}
+}
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
new file mode 100644
index 000000000..7d68deab1
--- /dev/null
+++ b/Crypto/src/crypto/engines/Salsa20Engine.cs
@@ -0,0 +1,299 @@
+using System;
+using System.Text;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+	/**
+	 * Implementation of Daniel J. Bernstein's Salsa20 stream cipher, Snuffle 2005
+	 */
+	public class Salsa20Engine
+		: IStreamCipher
+	{
+		/** Constants */
+		private const int StateSize = 16; // 16, 32 bit ints = 64 bytes
+
+		private readonly static byte[]
+			sigma = Strings.ToAsciiByteArray("expand 32-byte k"),
+			tau = Strings.ToAsciiByteArray("expand 16-byte k");
+
+		/*
+		 * 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;
+
+		/*
+		 * 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.
+		 */
+		public void Init(
+			bool				forEncryption, 
+			ICipherParameters	parameters)
+		{
+			/* 
+			 * Salsa20 encryption and decryption is completely
+			 * symmetrical, so the 'forEncryption' is 
+			 * irrelevant. (Like 90% of stream ciphers)
+			 */
+
+			ParametersWithIV ivParams = parameters as ParametersWithIV;
+
+			if (ivParams == null)
+				throw new ArgumentException("Salsa20 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");
+
+			KeyParameter key = ivParams.Parameters as KeyParameter;
+
+			if (key == null)
+				throw new ArgumentException("Salsa20 Init requires a key", "parameters");
+
+			workingKey = key.GetKey();
+			workingIV = iv;
+
+			SetKey(workingKey, workingIV);
+		}
+
+		public string AlgorithmName
+		{
+			get { return "Salsa20"; }
+		}
+
+		public byte ReturnByte(
+			byte input)
+		{
+			if (LimitExceeded())
+			{
+				throw new MaxBytesExceededException("2^70 byte limit per IV; Change IV");
+			}
+
+			if (index == 0)
+			{
+				GenerateKeyStream(keyStream);
+
+				if (++engineState[8] == 0)
+				{
+					++engineState[9];
+				}
+			}
+
+			byte output = (byte)(keyStream[index] ^ input);
+			index = (index + 1) & 63;
+
+			return output;
+		}
+
+		public void ProcessBytes(
+			byte[]	inBytes, 
+			int		inOff, 
+			int		len, 
+			byte[]	outBytes, 
+			int		outOff)
+		{
+			if (!initialised)
+			{
+				throw new InvalidOperationException(AlgorithmName + " not initialised");
+			}
+
+			if ((inOff + len) > inBytes.Length)
+			{
+				throw new DataLengthException("input buffer too short");
+			}
+
+			if ((outOff + len) > outBytes.Length)
+			{
+				throw new DataLengthException("output buffer too short");
+			}
+
+			if (LimitExceeded((uint)len))
+			{
+				throw new MaxBytesExceededException("2^70 byte limit per IV would be exceeded; Change IV");
+			}
+
+			for (int i = 0; i < len; i++)
+			{
+				if (index == 0)
+				{
+					GenerateKeyStream(keyStream);
+
+					if (++engineState[8] == 0)
+					{
+						++engineState[9];
+					}
+				}
+				outBytes[i+outOff] = (byte)(keyStream[index]^inBytes[i+inOff]);
+				index = (index + 1) & 63;
+			}
+		}
+
+		public void Reset()
+		{
+			SetKey(workingKey, workingIV);
+		}
+
+		// Private implementation
+
+		private void SetKey(byte[] keyBytes, byte[] ivBytes)
+		{
+			workingKey = keyBytes;
+			workingIV  = ivBytes;
+
+			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);
+
+			if (workingKey.Length == 32)
+			{
+				constants = sigma;
+				offset = 16;
+			}
+			else
+			{
+				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[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;
+		}
+
+		private void GenerateKeyStream(byte[] output)
+		{
+			SalsaCore(20, engineState, x);
+			Pack.UInt32_To_LE(x, output, 0);
+		}
+
+		internal static void SalsaCore(int rounds, uint[] state, uint[] x)
+		{
+            // TODO Exception if rounds odd?
+
+            Array.Copy(state, 0, x, 0, state.Length);
+
+			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);
+			}
+
+			for (int i = 0; i < StateSize; ++i)
+			{
+				x[i] += state[i];
+			}
+		}
+
+		private static uint R(uint x, int y)
+		{
+			return (x << y) | (x >> (32 - y));
+		}
+
+		private void ResetCounter()
+		{
+			cW0 = 0;
+			cW1 = 0;
+			cW2 = 0;
+		}
+
+		private bool LimitExceeded()
+		{
+			if (++cW0 == 0)
+			{
+				if (++cW1 == 0)
+				{
+					return (++cW2 & 0x20) != 0;          // 2^(32 + 32 + 6)
+				}
+			}
+
+			return false;
+		}
+
+		/*
+		 * this relies on the fact len will always be positive.
+		 */
+		private bool LimitExceeded(
+			uint len)
+		{
+			uint old = cW0;
+			cW0 += len;
+			if (cW0 < old)
+			{
+				if (++cW1 == 0)
+				{
+					return (++cW2 & 0x20) != 0;          // 2^(32 + 32 + 6)
+				}
+			}
+
+			return false;
+		}
+	}
+}
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/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
new file mode 100644
index 000000000..d467fbba5
--- /dev/null
+++ b/Crypto/src/crypto/engines/VMPCEngine.cs
@@ -0,0 +1,139 @@
+using System;
+
+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);
+		}
+	}
+}
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/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
new file mode 100644
index 000000000..0366401d1
--- /dev/null
+++ b/Crypto/src/crypto/generators/BaseKdfBytesGenerator.cs
@@ -0,0 +1,141 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+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;
+		}
+	}
+}
\ 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
new file mode 100644
index 000000000..756e8482a
--- /dev/null
+++ b/Crypto/src/crypto/generators/DHKeyGeneratorHelper.cs
@@ -0,0 +1,53 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+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);
+		}
+	}
+}
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
new file mode 100644
index 000000000..7860cbe33
--- /dev/null
+++ b/Crypto/src/crypto/generators/DHParametersHelper.cs
@@ -0,0 +1,234 @@
+using System;
+
+using Org.BouncyCastle.Math;
+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)
+			 */
+//			do
+//			{
+//				g = BigIntegers.CreateRandomInRange(BigInteger.Two, pMinusTwo, random);
+//			}
+//			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);
+
+				g = h.ModPow(BigInteger.Two, p);
+			}
+			while (g.Equals(BigInteger.One));
+
+			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
new file mode 100644
index 000000000..bb8ec591b
--- /dev/null
+++ b/Crypto/src/crypto/generators/DsaKeyPairGenerator.cs
@@ -0,0 +1,61 @@
+using System;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+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>.
+     */
+    public class DsaKeyPairGenerator
+		: IAsymmetricCipherKeyPairGenerator
+    {
+        private DsaKeyGenerationParameters param;
+
+		public void Init(
+			KeyGenerationParameters 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)
+
+			this.param = (DsaKeyGenerationParameters) parameters;
+        }
+
+		public AsymmetricCipherKeyPair GenerateKeyPair()
+        {
+			DsaParameters dsaParams = param.Parameters;
+
+			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));
+        }
+
+		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);
+		}
+	}
+}
diff --git a/Crypto/src/crypto/generators/DsaParametersGenerator.cs b/Crypto/src/crypto/generators/DsaParametersGenerator.cs
new file mode 100644
index 000000000..3e9d4f021
--- /dev/null
+++ b/Crypto/src/crypto/generators/DsaParametersGenerator.cs
@@ -0,0 +1,355 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+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.
+     */
+    public class DsaParametersGenerator
+    {
+		private int				L, N;
+        private int				certainty;
+        private SecureRandom	random;
+
+        /**
+         * initialise the key generator.
+         *
+         * @param size size of the key (range 2^512 -> 2^1024 - 64 bit increments)
+         * @param certainty measure of robustness of prime (for FIPS 186-2 compliance this should be at least 80).
+         * @param random random byte source.
+         */
+        public void Init(
+            int             size,
+            int             certainty,
+            SecureRandom    random)
+        {
+			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;
+		}
+
+//        /**
+//         * add value to b, returning the result in a. The a value is treated
+//         * as a BigInteger of length (a.Length * 8) bits. The result is
+//         * modulo 2^a.Length in case of overflow.
+//         */
+//        private static void Add(
+//            byte[]  a,
+//            byte[]  b,
+//            int     value)
+//        {
+//            int     x = (b[b.Length - 1] & 0xff) + value;
+//
+//            a[b.Length - 1] = (byte)x;
+//            x = (int) ((uint) x >>8);
+//
+//            for (int i = b.Length - 2; i >= 0; i--)
+//            {
+//                x += (b[i] & 0xff);
+//                a[i] = (byte)x;
+//                x = (int) ((uint) x >>8);
+//            }
+//        }
+
+		/**
+		 * 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()
+		{
+            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()
+		{
+// 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;
+
+// 1. Check that the (L, N) pair is in the list of acceptable (L, N pairs) (see Section 4.2). If
+//    the pair is not in the list, then return INVALID.
+			// Note: checked at initialisation
+			
+// 2. If (seedlen < N), then return INVALID.
+			// FIXME This should be configurable (must be >= N)
+			int seedlen = N;
+			byte[] seed = new byte[seedlen / 8];
+
+// 3. n = ceiling(L ⁄ outlen) – 1.
+			int n = (L - 1) / outlen;
+
+// 4. b = L – 1 – (n ∗ outlen).
+			int b = (L - 1) % outlen;
+
+			byte[] output = new byte[d.GetDigestSize()];
+			for (;;)
+			{
+// 5. Get an arbitrary sequence of seedlen bits as the domain_parameter_seed.
+				random.NextBytes(seed);
+
+// 6. U = Hash (domain_parameter_seed) mod 2^(N–1).
+				Hash(d, seed, output);
+				BigInteger U = new BigInteger(1, output).Mod(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));
+
+// 8. Test whether or not q is prime as specified in Appendix C.3.
+				// TODO Review C.3 for primality checking
+				if (!q.IsProbablePrime(certainty))
+				{
+// 9. If q is not a prime, then go to step 5.
+					continue;
+				}
+
+// 10. offset = 1.
+				// Note: 'offset' value managed incrementally
+				byte[] offset = Arrays.Clone(seed);
+
+// 11. For counter = 0 to (4L – 1) do
+				int counterLimit = 4 * L;
+				for (int counter = 0; counter < counterLimit; ++counter)
+				{
+// 11.1 For j = 0 to n do
+//      Vj = Hash ((domain_parameter_seed + offset + j) mod 2^seedlen).
+// 11.2 W = V0 + (V1 ∗ 2^outlen) + ... + (V^(n–1) ∗ 2^((n–1) ∗ outlen)) + ((Vn mod 2^b) ∗ 2^(n ∗ outlen)).
+					// TODO Assemble w as a byte array
+					BigInteger W = 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));
+
+// 11.4 c = X mod 2q.
+					BigInteger c = X.Mod(q.ShiftLeft(1));
+
+// 11.5 p = X - (c - 1). Comment: p ≡ 1 (mod 2q).
+					BigInteger p = X.Subtract(c.Subtract(BigInteger.One));
+
+					// 11.6 If (p < 2^(L - 1)), then go to step 11.9
+					if (p.BitLength != L)
+						continue;
+
+// 11.7 Test whether or not p is prime as specified in Appendix C.3.
+					// TODO Review C.3 for primality checking
+					if (p.IsProbablePrime(certainty))
+					{
+// 11.8 If p is determined to be prime, then return VALID and the values of p, q and
+//      (optionally) the values of domain_parameter_seed and counter.
+						// TODO Make configurable (8-bit unsigned)?
+//	                    int index = 1;
+//	                    BigInteger g = CalculateGenerator_FIPS186_3_Verifiable(d, p, q, seed, index);
+//	                    if (g != null)
+//	                    {
+//	                        // TODO Should 'index' be a part of the validation parameters?
+//	                        return new DsaParameters(p, q, g, new DsaValidationParameters(seed, counter));
+//	                    }
+
+						BigInteger g = CalculateGenerator_FIPS186_3_Unverifiable(p, q, random);
+						return new DsaParameters(p, q, g, new DsaValidationParameters(seed, counter));
+					}
+
+// 11.9 offset = offset + n + 1.      Comment: Increment offset; then, as part of
+//                                    the loop in step 11, increment counter; if
+//                                    counter < 4L, repeat steps 11.1 through 11.8.
+					// Note: 'offset' value already incremented in inner loop
+				}
+// 12. Go to step 5.
+			}
+		}
+
+		private static BigInteger CalculateGenerator_FIPS186_3_Unverifiable(BigInteger p, BigInteger q,
+			SecureRandom r)
+		{
+			return CalculateGenerator_FIPS186_2(p, q, r);
+		}
+
+		private static BigInteger CalculateGenerator_FIPS186_3_Verifiable(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;
+			}
+		}
+	}
+}
diff --git a/Crypto/src/crypto/generators/ECKeyPairGenerator.cs b/Crypto/src/crypto/generators/ECKeyPairGenerator.cs
new file mode 100644
index 000000000..d1e4b7cf6
--- /dev/null
+++ b/Crypto/src/crypto/generators/ECKeyPairGenerator.cs
@@ -0,0 +1,174 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+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.Math.EC;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    public class ECKeyPairGenerator
+		: IAsymmetricCipherKeyPairGenerator
+    {
+		private readonly string algorithm;
+
+		private ECDomainParameters parameters;
+		private DerObjectIdentifier publicKeyParamSet;
+        private SecureRandom random;
+
+		public ECKeyPairGenerator()
+			: this("EC")
+		{
+		}
+
+		public ECKeyPairGenerator(
+			string algorithm)
+		{
+			if (algorithm == null)
+				throw new ArgumentNullException("algorithm");
+
+			this.algorithm = VerifyAlgorithmName(algorithm);
+		}
+
+		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
+         * pair in accordance with X9.62 section 5.2.1 pages 26, 27.
+         */
+        public AsymmetricCipherKeyPair GenerateKeyPair()
+        {
+            BigInteger n = parameters.N;
+            BigInteger d;
+
+            do
+            {
+                d = new BigInteger(n.BitLength, random);
+            }
+            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);
+		}
+	}
+}
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
new file mode 100644
index 000000000..5878da64b
--- /dev/null
+++ b/Crypto/src/crypto/generators/GOST3410KeyPairGenerator.cs
@@ -0,0 +1,73 @@
+using System;
+
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+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;
+
+		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?
+				}
+
+				this.param = kgp;
+			}
+		}
+
+		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 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
new file mode 100644
index 000000000..2b4fb7efd
--- /dev/null
+++ b/Crypto/src/crypto/generators/Kdf1BytesGenerator.cs
@@ -0,0 +1,27 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+	/**
+	 * KFD2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+	 * <br/>
+	 * This implementation is based on IEEE P1363/ISO 18033.
+	 */
+	public class Kdf1BytesGenerator
+		: BaseKdfBytesGenerator
+	{
+		/**
+		 * Construct a KDF1 byte generator.
+		 *
+		 * @param digest the digest to be used as the source of derived keys.
+		 */
+		public Kdf1BytesGenerator(
+			IDigest  digest)
+			: base(0, digest)
+		{
+		}
+	}
+}
diff --git a/Crypto/src/crypto/generators/Kdf2BytesGenerator.cs b/Crypto/src/crypto/generators/Kdf2BytesGenerator.cs
new file mode 100644
index 000000000..be1cd158e
--- /dev/null
+++ b/Crypto/src/crypto/generators/Kdf2BytesGenerator.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+	/**
+	 * KDF2 generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+	 * <br/>
+	 * This implementation is based on IEEE P1363/ISO 18033.
+	 */
+	public class Kdf2BytesGenerator
+		: BaseKdfBytesGenerator
+	{
+		/**
+		* Construct a KDF2 bytes generator. Generates key material
+		* according to IEEE P1363 or ISO 18033 depending on the initialisation.
+		*
+		* @param digest the digest to be used as the source of derived keys.
+		*/
+		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
new file mode 100644
index 000000000..a00a6c8a6
--- /dev/null
+++ b/Crypto/src/crypto/generators/NaccacheSternKeyPairGenerator.cs
@@ -0,0 +1,333 @@
+using System;
+using System.Collections;
+
+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.Collections;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+	/**
+	 * Key generation parameters for NaccacheStern cipher. For details on this cipher, please see
+	 *
+	 * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+	 */
+	public class NaccacheSternKeyPairGenerator
+		: IAsymmetricCipherKeyPairGenerator
+	{
+		private static readonly int[] smallPrimes =
+		{
+			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
+		};
+
+		private NaccacheSternKeyGenerationParameters param;
+
+		/*
+		 * (non-Javadoc)
+		 *
+		 * @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#init(org.bouncycastle.crypto.KeyGenerationParameters)
+		 */
+		public void Init(KeyGenerationParameters parameters)
+		{
+			this.param = (NaccacheSternKeyGenerationParameters)parameters;
+		}
+
+		/*
+		 * (non-Javadoc)
+		 *
+		 * @see org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator#generateKeyPair()
+		 */
+		public AsymmetricCipherKeyPair GenerateKeyPair()
+		{
+			int strength = param.Strength;
+			SecureRandom rand = param.Random;
+			int certainty = param.Certainty;
+			bool debug = param.IsDebug;
+
+			if (debug)
+			{
+                System.Diagnostics.Debug.WriteLine("Fetching first " + param.CountSmallPrimes + " primes.");
+			}
+
+			IList smallPrimes = findFirstPrimes(param.CountSmallPrimes);
+
+			smallPrimes = permuteList(smallPrimes, rand);
+
+			BigInteger u = BigInteger.One;
+			BigInteger v = BigInteger.One;
+
+			for (int i = 0; i < smallPrimes.Count / 2; i++)
+			{
+				u = u.Multiply((BigInteger)smallPrimes[i]);
+			}
+			for (int i = smallPrimes.Count / 2; i < smallPrimes.Count; i++)
+			{
+				v = v.Multiply((BigInteger)smallPrimes[i]);
+			}
+
+			BigInteger sigma = u.Multiply(v);
+
+			// n = (2 a u _p + 1 ) ( 2 b v _q + 1)
+			// -> |n| = strength
+			// |2| = 1 in bits
+			// -> |a| * |b| = |n| - |u| - |v| - |_p| - |_q| - |2| -|2|
+			// remainingStrength = strength - sigma.bitLength() - _p.bitLength() -
+			// _q.bitLength() - 1 -1
+			int remainingStrength = strength - sigma.BitLength - 48;
+			BigInteger a = generatePrime(remainingStrength / 2 + 1, certainty, rand);
+			BigInteger b = generatePrime(remainingStrength / 2 + 1, certainty, rand);
+
+			BigInteger _p;
+			BigInteger _q;
+			BigInteger p;
+			BigInteger q;
+
+			long tries = 0;
+			if (debug)
+			{
+                System.Diagnostics.Debug.WriteLine("generating p and q");
+			}
+
+			BigInteger _2au = a.Multiply(u).ShiftLeft(1);
+			BigInteger _2bv = b.Multiply(v).ShiftLeft(1);
+
+			for (;;)
+			{
+				tries++;
+
+				_p = generatePrime(24, certainty, rand);
+
+				p = _p.Multiply(_2au).Add(BigInteger.One);
+
+				if (!p.IsProbablePrime(certainty))
+					continue;
+
+				for (;;)
+				{
+					_q = generatePrime(24, certainty, rand);
+
+					if (_p.Equals(_q))
+						continue;
+
+					q = _q.Multiply(_2bv).Add(BigInteger.One);
+
+					if (q.IsProbablePrime(certainty))
+						break;
+				}
+
+				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);
+					continue;
+				}
+
+				if (p.Multiply(q).BitLength < strength)
+				{
+					if (debug)
+					{
+                        System.Diagnostics.Debug.WriteLine("key size too small. Should be " + strength + " but is actually "
+							+ p.Multiply(q).BitLength);
+					}
+					continue;
+				}
+				break;
+			}
+
+			if (debug)
+			{
+                System.Diagnostics.Debug.WriteLine("needed " + tries + " tries to generate p and q.");
+			}
+
+			BigInteger n = p.Multiply(q);
+			BigInteger phi_n = p.Subtract(BigInteger.One).Multiply(q.Subtract(BigInteger.One));
+			BigInteger g;
+			tries = 0;
+			if (debug)
+			{
+                System.Diagnostics.Debug.WriteLine("generating g");
+			}
+			for (;;)
+			{
+				// TODO After the first loop, just regenerate one randomly-selected gPart each time?
+				IList gParts = Platform.CreateArrayList();
+				for (int ind = 0; ind != smallPrimes.Count; ind++)
+				{
+					BigInteger i = (BigInteger)smallPrimes[ind];
+					BigInteger e = phi_n.Divide(i);
+
+					for (;;)
+					{
+						tries++;
+
+						g = generatePrime(strength, certainty, rand);
+
+						if (!g.ModPow(e, n).Equals(BigInteger.One))
+						{
+							gParts.Add(g);
+							break;
+						}
+					}
+				}
+				g = BigInteger.One;
+				for (int i = 0; i < smallPrimes.Count; i++)
+				{
+					BigInteger gPart = (BigInteger) gParts[i];
+					BigInteger smallPrime = (BigInteger) smallPrimes[i];
+					g = g.Multiply(gPart.ModPow(sigma.Divide(smallPrime), n)).Mod(n);
+				}
+
+				// make sure that g is not divisible by p_i or q_i
+				bool divisible = false;
+				for (int i = 0; i < smallPrimes.Count; i++)
+				{
+					if (g.ModPow(phi_n.Divide((BigInteger)smallPrimes[i]), n).Equals(BigInteger.One))
+					{
+						if (debug)
+						{
+                            System.Diagnostics.Debug.WriteLine("g has order phi(n)/" + smallPrimes[i] + "\n g: " + g);
+						}
+						divisible = true;
+						break;
+					}
+				}
+
+				if (divisible)
+				{
+					continue;
+				}
+
+				// make sure that g has order > phi_n/4
+
+				//if (g.ModPow(phi_n.Divide(BigInteger.ValueOf(4)), n).Equals(BigInteger.One))
+				if (g.ModPow(phi_n.ShiftRight(2), n).Equals(BigInteger.One))
+				{
+					if (debug)
+					{
+                        System.Diagnostics.Debug.WriteLine("g has order phi(n)/4\n g:" + g);
+					}
+					continue;
+				}
+
+				if (g.ModPow(phi_n.Divide(_p), n).Equals(BigInteger.One))
+				{
+					if (debug)
+					{
+                        System.Diagnostics.Debug.WriteLine("g has order phi(n)/p'\n g: " + g);
+					}
+					continue;
+				}
+				if (g.ModPow(phi_n.Divide(_q), n).Equals(BigInteger.One))
+				{
+					if (debug)
+					{
+                        System.Diagnostics.Debug.WriteLine("g has order phi(n)/q'\n g: " + g);
+					}
+					continue;
+				}
+				if (g.ModPow(phi_n.Divide(a), n).Equals(BigInteger.One))
+				{
+					if (debug)
+					{
+                        System.Diagnostics.Debug.WriteLine("g has order phi(n)/a\n g: " + g);
+					}
+					continue;
+				}
+				if (g.ModPow(phi_n.Divide(b), n).Equals(BigInteger.One))
+				{
+					if (debug)
+					{
+                        System.Diagnostics.Debug.WriteLine("g has order phi(n)/b\n g: " + g);
+					}
+					continue;
+				}
+				break;
+			}
+			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("");
+			}
+
+			return new AsymmetricCipherKeyPair(new NaccacheSternKeyParameters(false, g, n, sigma.BitLength),
+				new NaccacheSternPrivateKeyParameters(g, n, sigma.BitLength, smallPrimes, phi_n));
+		}
+
+		private static BigInteger generatePrime(
+			int bitLength,
+			int certainty,
+			SecureRandom rand)
+		{
+			return new BigInteger(bitLength, certainty, rand);
+		}
+
+		/**
+		 * Generates a permuted ArrayList from the original one. The original List
+		 * is not modified
+		 *
+		 * @param arr
+		 *            the ArrayList to be permuted
+		 * @param rand
+		 *            the source of Randomness for permutation
+		 * @return a new ArrayList with the permuted elements.
+		 */
+		private static IList permuteList(
+			IList           arr,
+			SecureRandom    rand)
+		{
+            // TODO Create a utility method for generating permutation of first 'n' integers
+
+            IList retval = Platform.CreateArrayList(arr.Count);
+
+			foreach (object element in arr)
+			{
+				int index = rand.Next(retval.Count + 1);
+				retval.Insert(index, element);
+			}
+
+			return retval;
+		}
+
+		/**
+		 * Finds the first 'count' primes starting with 3
+		 *
+		 * @param count
+		 *            the number of primes to find
+		 * @return a vector containing the found primes as Integer
+		 */
+		private static IList findFirstPrimes(
+			int count)
+		{
+			IList primes = Platform.CreateArrayList(count);
+
+			for (int i = 0; i != count; i++)
+			{
+				primes.Add(BigInteger.ValueOf(smallPrimes[i]));
+			}
+
+			return primes;
+		}
+
+	}
+}
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
new file mode 100644
index 000000000..d2da3f6fc
--- /dev/null
+++ b/Crypto/src/crypto/generators/Pkcs12ParametersGenerator.cs
@@ -0,0 +1,245 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+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 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);
+		}
+	}
+}
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
new file mode 100644
index 000000000..58d7b5c37
--- /dev/null
+++ b/Crypto/src/crypto/generators/Pkcs5S2ParametersGenerator.cs
@@ -0,0 +1,172 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Utilities;
+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 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);
+		}
+	}
+}
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
new file mode 100644
index 000000000..3074aed04
--- /dev/null
+++ b/Crypto/src/crypto/generators/RsaKeyPairGenerator.cs
@@ -0,0 +1,139 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Generators
+{
+    /**
+     * an RSA key pair generator.
+     */
+    public class RsaKeyPairGenerator
+		: IAsymmetricCipherKeyPairGenerator
+    {
+		private static readonly BigInteger DefaultPublicExponent = BigInteger.ValueOf(0x10001);
+		private const int DefaultTests = 12;
+
+		private RsaKeyGenerationParameters param;
+
+		public void Init(
+            KeyGenerationParameters parameters)
+        {
+			if (parameters is RsaKeyGenerationParameters)
+			{
+				this.param = (RsaKeyGenerationParameters)parameters;
+			}
+			else
+			{
+				this.param = new RsaKeyGenerationParameters(
+					DefaultPublicExponent, parameters.Random, parameters.Strength, DefaultTests);
+			}
+        }
+
+		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);
+
+				if (p.Mod(e).Equals(BigInteger.One))
+					continue;
+
+				if (!p.IsProbablePrime(param.Certainty))
+					continue;
+
+				if (e.Gcd(p.Subtract(BigInteger.One)).Equals(BigInteger.One)) 
+					break;
+			}
+
+            //
+            // Generate a modulus of the required length
+            //
+            for (;;)
+            {
+                // Generate q, prime and (q-1) relatively prime to e,
+                // and not equal to p
+                //
+                for (;;)
+                {
+					q = new BigInteger(qbitlength, 1, param.Random);
+
+					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;
+				}
+
+                //
+                // calculate the modulus
+                //
+                n = p.Multiply(q);
+
+                if (n.BitLength == param.Strength)
+					break;
+
+                //
+                // if we Get here our primes aren't big enough, make the largest
+                // of the two p and try again
+                //
+                p = p.Max(q);
+            }
+
+			if (p.CompareTo(q) < 0)
+			{
+				phi = p;
+				p = q;
+				q = phi;
+			}
+
+            pSub1 = p.Subtract(BigInteger.One);
+            qSub1 = q.Subtract(BigInteger.One);
+            phi = pSub1.Multiply(qSub1);
+
+            //
+            // calculate the private exponent
+            //
+            d = e.ModInverse(phi);
+
+            //
+            // calculate the CRT factors
+            //
+            BigInteger dP, dQ, qInv;
+
+            dP = d.Remainder(pSub1);
+            dQ = d.Remainder(qSub1);
+            qInv = q.ModInverse(p);
+
+            return new AsymmetricCipherKeyPair(
+                new RsaKeyParameters(false, n, e),
+                new RsaPrivateCrtKeyParameters(n, e, d, p, q, dP, dQ, qInv));
+        }
+    }
+
+}
diff --git a/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
new file mode 100644
index 000000000..bf7effb0a
--- /dev/null
+++ b/Crypto/src/crypto/io/CipherStream.cs
@@ -0,0 +1,237 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crypto.IO
+{
+    public class CipherStream
+		: Stream
+    {
+        internal Stream stream;
+        internal IBufferedCipher inCipher, outCipher;
+        private byte[] mInBuf;
+		private int mInPos;
+		private bool inStreamEnded;
+
+		public CipherStream(
+            Stream			stream,
+            IBufferedCipher	readCipher,
+            IBufferedCipher	writeCipher)
+        {
+            this.stream = stream;
+
+			if (readCipher != null)
+			{
+				this.inCipher = readCipher;
+				mInBuf = null;
+			}
+
+			if (writeCipher != null)
+			{
+				this.outCipher = writeCipher;
+			}
+		}
+
+		public IBufferedCipher ReadCipher
+		{
+			get { return inCipher; }
+		}
+
+		public IBufferedCipher WriteCipher
+		{
+			get { return outCipher; }
+		}
+
+		public override int ReadByte()
+        {
+            if (inCipher == null)
+                return stream.ReadByte();
+
+			if (mInBuf == null || mInPos >= mInBuf.Length)
+			{
+				if (!FillInBuf())
+					return -1;
+            }
+
+			return mInBuf[mInPos++];
+        }
+
+		public override int Read(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+        {
+            if (inCipher == null)
+                return stream.Read(buffer, offset, count);
+
+			int num = 0;
+			while (num < count)
+			{
+				if (mInBuf == null || mInPos >= mInBuf.Length)
+				{
+					if (!FillInBuf())
+						break;
+				}
+
+				int numToCopy = System.Math.Min(count - num, mInBuf.Length - mInPos);
+				Array.Copy(mInBuf, mInPos, buffer, offset + num, numToCopy);
+				mInPos += numToCopy;
+				num += numToCopy;
+			}
+
+			return num;
+		}
+
+		private bool FillInBuf()
+        {
+			if (inStreamEnded)
+				return false;
+
+			mInPos = 0;
+
+			do
+			{
+				mInBuf = ReadAndProcessBlock();
+			}
+			while (!inStreamEnded && mInBuf == null);
+
+			return mInBuf != null;
+		}
+
+		private byte[] ReadAndProcessBlock()
+		{
+			int blockSize = inCipher.GetBlockSize();
+			int readSize = (blockSize == 0) ? 256 : blockSize;
+
+			byte[] block = new byte[readSize];
+			int numRead = 0;
+			do
+			{
+				int count = stream.Read(block, numRead, block.Length - numRead);
+				if (count < 1)
+				{
+					inStreamEnded = true;
+					break;
+				}
+				numRead += count;
+			}
+			while (numRead < block.Length);
+
+			Debug.Assert(inStreamEnded || numRead == block.Length);
+
+			byte[] bytes = inStreamEnded
+				?	inCipher.DoFinal(block, 0, numRead)
+				:	inCipher.ProcessBytes(block);
+
+			if (bytes != null && bytes.Length == 0)
+			{
+				bytes = null;
+			}
+
+			return bytes;
+		}
+
+		public override void Write(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+        {
+			Debug.Assert(buffer != null);
+			Debug.Assert(0 <= offset && offset <= buffer.Length);
+			Debug.Assert(count >= 0);
+
+			int end = offset + count;
+
+			Debug.Assert(0 <= end && end <= buffer.Length);
+
+			if (outCipher == null)
+            {
+                stream.Write(buffer, offset, count);
+                return;
+            }
+
+			byte[] data = outCipher.ProcessBytes(buffer, offset, count);
+			if (data != null)
+			{
+				stream.Write(data, 0, data.Length);
+			}
+		}
+
+		public override void WriteByte(
+			byte b)
+        {
+            if (outCipher == null)
+            {
+                stream.WriteByte(b);
+                return;
+            }
+
+			byte[] data = outCipher.ProcessByte(b);
+			if (data != null)
+			{
+				stream.Write(data, 0, data.Length);
+			}
+		}
+
+		public override bool CanRead
+        {
+            get { return stream.CanRead && (inCipher != null); }
+        }
+
+		public override bool CanWrite
+        {
+            get { return stream.CanWrite && (outCipher != null); }
+        }
+
+		public override bool CanSeek
+        {
+            get { return false; }
+        }
+
+		public sealed override long Length
+		{
+			get { throw new NotSupportedException(); }
+		}
+
+		public sealed override long Position
+        {
+            get { throw new NotSupportedException(); }
+            set { throw new NotSupportedException(); }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                if (outCipher != null)
+                {
+                    byte[] data = outCipher.DoFinal();
+                    stream.Write(data, 0, data.Length);
+                    stream.Flush();
+                }
+                stream.Dispose();
+            }
+        }
+
+		public override void Flush()
+        {
+			// Note: outCipher.DoFinal is only called during Close()
+			stream.Flush();
+        }
+
+		public sealed override long Seek(
+			long		offset,
+			SeekOrigin	origin)
+		{
+			throw new NotSupportedException();
+		}
+
+		public sealed override void SetLength(
+			long length)
+		{
+			throw new NotSupportedException();
+		}
+    }
+}
diff --git a/Crypto/src/crypto/io/DigestStream.cs b/Crypto/src/crypto/io/DigestStream.cs
new file mode 100644
index 000000000..a5b31f95c
--- /dev/null
+++ b/Crypto/src/crypto/io/DigestStream.cs
@@ -0,0 +1,140 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.IO
+{
+	public class DigestStream
+		: Stream
+	{
+		protected readonly Stream stream;
+		protected readonly IDigest inDigest;
+		protected readonly IDigest outDigest;
+
+		public DigestStream(
+			Stream	stream,
+			IDigest	readDigest,
+			IDigest	writeDigest)
+		{
+			this.stream = stream;
+			this.inDigest = readDigest;
+			this.outDigest = writeDigest;
+		}
+
+		public virtual IDigest ReadDigest()
+		{
+			return inDigest;
+		}
+
+		public virtual IDigest WriteDigest()
+		{
+			return outDigest;
+		}
+
+		public override int Read(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+		{
+			int n = stream.Read(buffer, offset, count);
+			if (inDigest != null)
+			{
+				if (n > 0)
+				{
+					inDigest.BlockUpdate(buffer, offset, n);
+				}
+			}
+			return n;
+		}
+
+		public override int ReadByte()
+		{
+			int b = stream.ReadByte();
+			if (inDigest != null)
+			{
+				if (b >= 0)
+				{
+					inDigest.Update((byte)b);
+				}
+			}
+			return b;
+		}
+
+		public override void Write(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+		{
+			if (outDigest != null)
+			{
+				if (count > 0)
+				{
+					outDigest.BlockUpdate(buffer, offset, count);
+				}
+			}
+			stream.Write(buffer, offset, count);
+		}
+
+		public override void WriteByte(
+			byte b)
+		{
+			if (outDigest != null)
+			{
+				outDigest.Update(b);
+			}
+			stream.WriteByte(b);
+		}
+
+		public override bool CanRead
+		{
+			get { return stream.CanRead; }
+		}
+
+		public override bool CanWrite
+		{
+			get { return stream.CanWrite; }
+		}
+
+		public override bool CanSeek
+		{
+			get { return stream.CanSeek; }
+		}
+
+		public override long Length
+		{
+			get { return stream.Length; }
+		}
+
+		public override long Position
+		{
+			get { return stream.Position; }
+			set { stream.Position = value; }
+		}
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                stream.Dispose();
+            }
+        }
+
+		public override  void Flush()
+		{
+			stream.Flush();
+		}
+
+		public override long Seek(
+			long		offset,
+			SeekOrigin	origin)
+		{
+			return stream.Seek(offset, origin);
+		}
+
+		public override void SetLength(
+			long length)
+		{
+			stream.SetLength(length);
+		}
+	}
+}
+
diff --git a/Crypto/src/crypto/io/MacStream.cs b/Crypto/src/crypto/io/MacStream.cs
new file mode 100644
index 000000000..419eafb77
--- /dev/null
+++ b/Crypto/src/crypto/io/MacStream.cs
@@ -0,0 +1,139 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.IO
+{
+	public class MacStream
+		: Stream
+	{
+		protected readonly Stream stream;
+		protected readonly IMac inMac;
+		protected readonly IMac outMac;
+
+		public MacStream(
+			Stream	stream,
+			IMac	readMac,
+			IMac	writeMac)
+		{
+			this.stream = stream;
+			this.inMac = readMac;
+			this.outMac = writeMac;
+		}
+
+		public virtual IMac ReadMac()
+		{
+			return inMac;
+		}
+
+		public virtual IMac WriteMac()
+		{
+			return outMac;
+		}
+
+		public override int Read(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+		{
+			int n = stream.Read(buffer, offset, count);
+			if (inMac != null)
+			{
+				if (n > 0)
+				{
+					inMac.BlockUpdate(buffer, offset, n);
+				}
+			}
+			return n;
+		}
+
+		public override int ReadByte()
+		{
+			int b = stream.ReadByte();
+			if (inMac != null)
+			{
+				if (b >= 0)
+				{
+					inMac.Update((byte)b);
+				}
+			}
+			return b;
+		}
+
+		public override void Write(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+		{
+			if (outMac != null)
+			{
+				if (count > 0)
+				{
+					outMac.BlockUpdate(buffer, offset, count);
+				}
+			}
+			stream.Write(buffer, offset, count);
+		}
+
+		public override void WriteByte(byte b)
+		{
+			if (outMac != null)
+			{
+				outMac.Update(b);
+			}
+			stream.WriteByte(b);
+		}
+
+		public override bool CanRead
+		{
+			get { return stream.CanRead; }
+		}
+
+		public override bool CanWrite
+		{
+			get { return stream.CanWrite; }
+		}
+
+		public override bool CanSeek
+		{
+			get { return stream.CanSeek; }
+		}
+
+		public override long Length
+		{
+			get { return stream.Length; }
+		}
+
+		public override long Position
+		{
+			get { return stream.Position; }
+			set { stream.Position = value; }
+		}
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                stream.Dispose();
+            }
+        }
+
+		public override void Flush()
+		{
+			stream.Flush();
+		}
+
+		public override long Seek(
+			long		offset,
+			SeekOrigin	origin)
+		{
+			return stream.Seek(offset,origin);
+		}
+
+		public override void SetLength(
+			long length)
+		{
+			stream.SetLength(length);
+		}
+	}
+}
+
diff --git a/Crypto/src/crypto/io/SignerStream.cs b/Crypto/src/crypto/io/SignerStream.cs
new file mode 100644
index 000000000..8be8ca84a
--- /dev/null
+++ b/Crypto/src/crypto/io/SignerStream.cs
@@ -0,0 +1,140 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.IO
+{
+	public class SignerStream
+		: Stream
+	{
+		protected readonly Stream stream;
+		protected readonly ISigner inSigner;
+		protected readonly ISigner outSigner;
+
+		public SignerStream(
+			Stream	stream,
+			ISigner	readSigner,
+			ISigner	writeSigner)
+		{
+			this.stream = stream;
+			this.inSigner = readSigner;
+			this.outSigner = writeSigner;
+		}
+
+		public virtual ISigner ReadSigner()
+		{
+			return inSigner;
+		}
+
+		public virtual ISigner WriteSigner()
+		{
+			return outSigner;
+		}
+
+		public override int Read(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+		{
+			int n = stream.Read(buffer, offset, count);
+			if (inSigner != null)
+			{
+				if (n > 0)
+				{
+					inSigner.BlockUpdate(buffer, offset, n);
+				}
+			}
+			return n;
+		}
+
+		public override int ReadByte()
+		{
+			int b = stream.ReadByte();
+			if (inSigner != null)
+			{
+				if (b >= 0)
+				{
+					inSigner.Update((byte)b);
+				}
+			}
+			return b;
+		}
+
+		public override void Write(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+		{
+			if (outSigner != null)
+			{
+				if (count > 0)
+				{
+					outSigner.BlockUpdate(buffer, offset, count);
+				}
+			}
+			stream.Write(buffer, offset, count);
+		}
+
+		public override void WriteByte(
+			byte b)
+		{
+			if (outSigner != null)
+			{
+				outSigner.Update(b);
+			}
+			stream.WriteByte(b);
+		}
+
+		public override bool CanRead
+		{
+			get { return stream.CanRead; }
+		}
+
+		public override bool CanWrite
+		{
+			get { return stream.CanWrite; }
+		}
+
+		public override bool CanSeek
+		{
+			get { return stream.CanSeek; }
+		}
+
+		public override long Length
+		{
+			get { return stream.Length; }
+		}
+
+		public override long Position
+		{
+			get { return stream.Position; }
+			set { stream.Position = value; }
+		}
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                stream.Dispose();
+            }
+        }
+
+		public override  void Flush()
+		{
+			stream.Flush();
+		}
+
+		public override long Seek(
+			long		offset,
+			SeekOrigin	origin)
+		{
+			return stream.Seek(offset, origin);
+		}
+
+		public override void SetLength(
+			long length)
+		{
+			stream.SetLength(length);
+		}
+	}
+}
+
diff --git a/Crypto/src/crypto/macs/CMac.cs b/Crypto/src/crypto/macs/CMac.cs
new file mode 100644
index 000000000..ea1ce88f5
--- /dev/null
+++ b/Crypto/src/crypto/macs/CMac.cs
@@ -0,0 +1,240 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+
+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();
+		}
+	}
+}
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/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
new file mode 100644
index 000000000..3f9b0cef0
--- /dev/null
+++ b/Crypto/src/crypto/macs/HMac.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Macs
+{
+    /**
+    * HMAC implementation based on RFC2104
+    *
+    * H(K XOR opad, H(K XOR ipad, text))
+    */
+    public class HMac
+		: IMac
+    {
+        private const byte IPAD = (byte)0x36;
+        private const byte OPAD = (byte)0x5C;
+
+        private readonly IDigest digest;
+        private readonly int digestSize;
+        private readonly int blockLength;
+
+		private readonly byte[] inputPad;
+        private readonly byte[] outputPad;
+
+        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];
+        }
+
+        public string AlgorithmName
+        {
+            get { return digest.AlgorithmName + "/HMAC"; }
+        }
+
+		public IDigest GetUnderlyingDigest()
+        {
+            return digest;
+        }
+
+        public void Init(
+            ICipherParameters parameters)
+        {
+            digest.Reset();
+
+            byte[] key = ((KeyParameter)parameters).GetKey();
+			int keyLength = key.Length;
+
+            if (keyLength > blockLength)
+            {
+                digest.BlockUpdate(key, 0, key.Length);
+                digest.DoFinal(inputPad, 0);
+
+				keyLength = digestSize;
+            }
+            else
+            {
+				Array.Copy(key, 0, inputPad, 0, keyLength);
+            }
+
+			Array.Clear(inputPad, keyLength, blockLength - keyLength);
+            Array.Copy(inputPad, 0, outputPad, 0, blockLength);
+
+			xor(inputPad, IPAD);
+			xor(outputPad, OPAD);
+
+			// Initialise the digest
+			digest.BlockUpdate(inputPad, 0, inputPad.Length);
+        }
+
+        public int GetMacSize()
+        {
+            return digestSize;
+        }
+
+        public void Update(
+            byte input)
+        {
+            digest.Update(input);
+        }
+
+        public void BlockUpdate(
+            byte[] input,
+            int inOff,
+            int len)
+        {
+            digest.BlockUpdate(input, inOff, len);
+        }
+
+        public 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);
+
+            return len;
+        }
+
+        /**
+        * Reset the mac generator.
+        */
+        public void Reset()
+        {
+			// Reset underlying digest
+            digest.Reset();
+
+			// Initialise the digest
+            digest.BlockUpdate(inputPad, 0, inputPad.Length);
+        }
+
+		private static void xor(byte[] a, byte n)
+		{
+			for (int i = 0; i < a.Length; ++i)
+            {
+                a[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/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
new file mode 100644
index 000000000..0bbc0cb24
--- /dev/null
+++ b/Crypto/src/crypto/modes/CbcBlockCipher.cs
@@ -0,0 +1,231 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+    /**
+    * implements Cipher-Block-Chaining (CBC) mode on top of a simple cipher.
+    */
+    public class CbcBlockCipher
+		: IBlockCipher
+    {
+        private byte[]			IV, cbcV, cbcNextV;
+		private int				blockSize;
+        private IBlockCipher	cipher;
+        private bool			encrypting;
+
+        /**
+        * Basic constructor.
+        *
+        * @param cipher the block cipher to be used as the basis of chaining.
+        */
+        public CbcBlockCipher(
+            IBlockCipher cipher)
+        {
+            this.cipher = cipher;
+            this.blockSize = cipher.GetBlockSize();
+
+            this.IV = new byte[blockSize];
+            this.cbcV = new byte[blockSize];
+            this.cbcNextV = new byte[blockSize];
+        }
+
+        /**
+        * return the underlying block cipher that we are wrapping.
+        *
+        * @return the underlying block cipher that we are wrapping.
+        */
+        public IBlockCipher GetUnderlyingCipher()
+        {
+            return cipher;
+        }
+
+        /**
+        * Initialise the cipher and, possibly, the initialisation vector (IV).
+        * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+        *
+        * @param 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 void Init(
+            bool forEncryption,
+            ICipherParameters parameters)
+        {
+            this.encrypting = forEncryption;
+
+            if (parameters is ParametersWithIV)
+            {
+                ParametersWithIV ivParam = (ParametersWithIV)parameters;
+                byte[]      iv = ivParam.GetIV();
+
+                if (iv.Length != blockSize)
+                {
+                    throw new ArgumentException("initialisation vector must be the same length as block size");
+                }
+
+                Array.Copy(iv, 0, IV, 0, iv.Length);
+
+				parameters = ivParam.Parameters;
+            }
+
+			Reset();
+
+			cipher.Init(encrypting, parameters);
+        }
+
+		/**
+        * return the algorithm name and mode.
+        *
+        * @return the name of the underlying algorithm followed by "/CBC".
+        */
+        public string AlgorithmName
+        {
+            get { return cipher.AlgorithmName + "/CBC"; }
+        }
+
+		public bool IsPartialBlockOkay
+		{
+			get { return false; }
+		}
+
+		/**
+        * return the block size of the underlying cipher.
+        *
+        * @return the block size of the underlying cipher.
+        */
+        public int GetBlockSize()
+        {
+            return cipher.GetBlockSize();
+        }
+
+        /**
+        * Process one block of input from the array in and write it to
+        * the out array.
+        *
+        * @param in the array containing the input data.
+        * @param inOff offset into the in array the data starts at.
+        * @param out the array the output data will be copied into.
+        * @param outOff the offset into the out array the output will start at.
+        * @exception DataLengthException if there isn't enough data in in, or
+        * space in out.
+        * @exception 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 (encrypting)
+				?	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()
+        {
+            Array.Copy(IV, 0, cbcV, 0, IV.Length);
+			Array.Clear(cbcNextV, 0, cbcNextV.Length);
+
+            cipher.Reset();
+        }
+
+        /**
+        * Do the appropriate chaining step for CBC mode encryption.
+        *
+        * @param in the array containing the data to be encrypted.
+        * @param inOff offset into the in array the data starts at.
+        * @param out the array the encrypted data will be copied into.
+        * @param outOff the offset into the out array the output will start at.
+        * @exception DataLengthException if there isn't enough data in in, or
+        * space in out.
+        * @exception 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");
+            }
+
+            /*
+            * XOR the cbcV and the input,
+            * then encrypt the cbcV
+            */
+            for (int i = 0; i < blockSize; i++)
+            {
+                cbcV[i] ^= input[inOff + i];
+            }
+
+            int length = cipher.ProcessBlock(cbcV, 0, outBytes, outOff);
+
+            /*
+            * copy ciphertext to cbcV
+            */
+            Array.Copy(outBytes, outOff, cbcV, 0, cbcV.Length);
+
+            return length;
+        }
+
+        /**
+        * Do the appropriate chaining step for CBC mode decryption.
+        *
+        * @param in the array containing the data to be decrypted.
+        * @param inOff offset into the in array the data starts at.
+        * @param out the array the decrypted data will be copied into.
+        * @param outOff the offset into the out array the output will start at.
+        * @exception DataLengthException if there isn't enough data in in, or
+        * space in out.
+        * @exception 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");
+            }
+
+            Array.Copy(input, inOff, cbcNextV, 0, blockSize);
+
+            int length = cipher.ProcessBlock(input, inOff, outBytes, outOff);
+
+            /*
+            * XOR the cbcV and the output
+            */
+            for (int i = 0; i < blockSize; i++)
+            {
+                outBytes[outOff + i] ^= cbcV[i];
+            }
+
+            /*
+            * swap the back up buffer into next position
+            */
+            byte[]  tmp;
+
+            tmp = cbcV;
+            cbcV = cbcNextV;
+            cbcNextV = tmp;
+
+            return length;
+        }
+    }
+
+}
diff --git a/Crypto/src/crypto/modes/CcmBlockCipher.cs b/Crypto/src/crypto/modes/CcmBlockCipher.cs
new file mode 100644
index 000000000..abfde237e
--- /dev/null
+++ b/Crypto/src/crypto/modes/CcmBlockCipher.cs
@@ -0,0 +1,345 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+    /**
+    * Implements the Counter with Cipher Block Chaining mode (CCM) detailed in
+    * NIST Special Publication 800-38C.
+    * <p>
+    * <b>Note</b>: this mode is a packet mode - it needs all the data up front.
+	* </p>
+    */
+    public class CcmBlockCipher
+		: IAeadBlockCipher
+    {
+		private static readonly int BlockSize = 16;
+
+		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();
+
+        /**
+        * Basic constructor.
+        *
+        * @param cipher the block cipher to be used.
+        */
+        public CcmBlockCipher(
+			IBlockCipher cipher)
+        {
+            this.cipher = cipher;
+            this.macBlock = new byte[BlockSize];
+
+            if (cipher.GetBlockSize() != BlockSize)
+                throw new ArgumentException("cipher required with a block size of " + BlockSize + ".");
+        }
+
+        /**
+        * return the underlying block cipher that we are wrapping.
+        *
+        * @return the underlying block cipher that we are wrapping.
+        */
+        public virtual IBlockCipher GetUnderlyingCipher()
+        {
+            return cipher;
+        }
+
+        public virtual void Init(
+			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");
+			}
+        }
+
+		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);
+		}
+
+		/**
+        * Returns a byte array containing the mac calculated as part of the
+        * last encrypt or decrypt operation.
+        *
+        * @return the last mac calculated.
+        */
+        public virtual byte[] GetMac()
+        {
+			byte[] mac = new byte[macSize];
+
+			Array.Copy(macBlock, 0, mac, 0, mac.Length);
+
+			return mac;
+        }
+
+		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)
+        {
+            if (keyParam == null)
+                throw new InvalidOperationException("CCM cipher unitialized.");
+
+			IBlockCipher ctrCipher = new SicBlockCipher(cipher);
+            byte[] iv = new byte[BlockSize];
+            byte[] output;
+
+            iv[0] = (byte)(((15 - nonce.Length) - 1) & 0x7);
+
+            Array.Copy(nonce, 0, iv, 1, nonce.Length);
+
+			ctrCipher.Init(forEncryption, new ParametersWithIV(keyParam, iv));
+
+			if (forEncryption)
+            {
+                int index = inOff;
+                int outOff = 0;
+
+                output = new byte[inLen + macSize];
+
+                calculateMac(input, inOff, inLen, macBlock);
+
+                ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0);   // S0
+
+                while (index < inLen - BlockSize)                   // S1...
+                {
+                    ctrCipher.ProcessBlock(input, index, output, outOff);
+                    outOff += BlockSize;
+                    index += BlockSize;
+                }
+
+                byte[] block = new byte[BlockSize];
+
+                Array.Copy(input, index, block, 0, inLen - index);
+
+                ctrCipher.ProcessBlock(block, 0, block, 0);
+
+                Array.Copy(block, 0, output, outOff, inLen - index);
+
+                outOff += inLen - index;
+
+                Array.Copy(macBlock, 0, output, outOff, output.Length - outOff);
+            }
+            else
+            {
+                int index = inOff;
+                int outOff = 0;
+
+                output = new byte[inLen - macSize];
+
+                Array.Copy(input, inOff + inLen - macSize, macBlock, 0, macSize);
+
+                ctrCipher.ProcessBlock(macBlock, 0, macBlock, 0);
+
+                for (int i = macSize; i != macBlock.Length; i++)
+                {
+                    macBlock[i] = 0;
+                }
+
+                while (outOff < output.Length - BlockSize)
+                {
+                    ctrCipher.ProcessBlock(input, index, output, outOff);
+                    outOff += BlockSize;
+                    index += BlockSize;
+                }
+
+                byte[] block = new byte[BlockSize];
+
+                Array.Copy(input, index, block, 0, output.Length - outOff);
+
+                ctrCipher.ProcessBlock(block, 0, block, 0);
+
+                Array.Copy(block, 0, output, outOff, output.Length - outOff);
+
+                byte[] calculatedMacBlock = new byte[BlockSize];
+
+                calculateMac(output, 0, output.Length, calculatedMacBlock);
+
+				if (!Arrays.ConstantTimeAreEqual(macBlock, calculatedMacBlock))
+                    throw new InvalidCipherTextException("mac check in CCM failed");
+            }
+
+			return output;
+        }
+
+		private int calculateMac(byte[] data, int dataOff, int dataLen, byte[] macBlock)
+        {
+			IMac cMac = new CbcBlockCipherMac(cipher, macSize * 8);
+
+			cMac.Init(keyParam);
+
+			//
+            // build b0
+            //
+            byte[] b0 = new byte[16];
+
+			if (hasAssociatedText())
+            {
+                b0[0] |= 0x40;
+            }
+
+            b0[0] |= (byte)((((cMac.GetMacSize() - 2) / 2) & 0x7) << 3);
+
+            b0[0] |= (byte)(((15 - nonce.Length) - 1) & 0x7);
+
+            Array.Copy(nonce, 0, b0, 1, nonce.Length);
+
+            int q = dataLen;
+            int count = 1;
+            while (q > 0)
+            {
+                b0[b0.Length - count] = (byte)(q & 0xff);
+                q >>= 8;
+                count++;
+            }
+
+            cMac.BlockUpdate(b0, 0, b0.Length);
+
+            //
+            // process associated text
+            //
+			if (hasAssociatedText())
+            {
+                int extra;
+
+                if (associatedText.Length < ((1 << 16) - (1 << 8)))
+                {
+                    cMac.Update((byte)(associatedText.Length >> 8));
+                    cMac.Update((byte)associatedText.Length);
+
+                    extra = 2;
+                }
+                else // can't go any higher than 2^32
+                {
+                    cMac.Update((byte)0xff);
+                    cMac.Update((byte)0xfe);
+                    cMac.Update((byte)(associatedText.Length >> 24));
+                    cMac.Update((byte)(associatedText.Length >> 16));
+                    cMac.Update((byte)(associatedText.Length >> 8));
+                    cMac.Update((byte)associatedText.Length);
+
+                    extra = 6;
+                }
+
+                cMac.BlockUpdate(associatedText, 0, associatedText.Length);
+
+                extra = (extra + associatedText.Length) % 16;
+                if (extra != 0)
+                {
+                    for (int i = 0; i != 16 - extra; i++)
+                    {
+                        cMac.Update((byte)0x00);
+                    }
+                }
+            }
+
+            //
+            // add the text
+            //
+            cMac.BlockUpdate(data, dataOff, dataLen);
+
+            return cMac.DoFinal(macBlock, 0);
+        }
+
+		private bool hasAssociatedText()
+		{
+			return associatedText != null && associatedText.Length != 0;
+		}
+    }
+}
diff --git a/Crypto/src/crypto/modes/CfbBlockCipher.cs b/Crypto/src/crypto/modes/CfbBlockCipher.cs
new file mode 100644
index 000000000..b400a72f4
--- /dev/null
+++ b/Crypto/src/crypto/modes/CfbBlockCipher.cs
@@ -0,0 +1,218 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+    /**
+    * implements a Cipher-FeedBack (CFB) mode on top of a simple cipher.
+    */
+    public class CfbBlockCipher
+		: IBlockCipher
+    {
+        private byte[]	IV;
+        private byte[]	cfbV;
+        private byte[]	cfbOutV;
+		private bool	encrypting;
+
+		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 CfbBlockCipher(
+            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()];
+        }
+        /**
+        * return the underlying block cipher that we are wrapping.
+        *
+        * @return the underlying block cipher that we are wrapping.
+        */
+        public IBlockCipher GetUnderlyingCipher()
+        {
+            return cipher;
+        }
+        /**
+        * Initialise the cipher and, possibly, the initialisation vector (IV).
+        * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+        * An IV which is too short is handled in FIPS compliant fashion.
+        *
+        * @param 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 void Init(
+            bool forEncryption,
+            ICipherParameters parameters)
+        {
+            this.encrypting = forEncryption;
+            if (parameters is ParametersWithIV)
+            {
+                ParametersWithIV ivParam = (ParametersWithIV) parameters;
+                byte[] iv = ivParam.GetIV();
+                int diff = IV.Length - iv.Length;
+                Array.Copy(iv, 0, IV, diff, iv.Length);
+                Array.Clear(IV, 0, diff);
+
+                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[]	output,
+            int		outOff)
+        {
+            return (encrypting)
+				?	EncryptBlock(input, inOff, output, outOff)
+				:	DecryptBlock(input, inOff, output, outOff);
+        }
+
+		/**
+        * Do the appropriate processing for CFB mode encryption.
+        *
+        * @param in the array containing the data to be encrypted.
+        * @param inOff offset into the in array the data starts at.
+        * @param out the array the encrypted data will be copied into.
+        * @param outOff the offset into the out array the output will start at.
+        * @exception DataLengthException if there isn't enough data in in, or
+        * space in out.
+        * @exception InvalidOperationException if the cipher isn't initialised.
+        * @return the number of bytes processed and produced.
+        */
+        public 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");
+            }
+            cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
+            //
+            // XOR the cfbV with the plaintext producing the ciphertext
+            //
+            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;
+        }
+        /**
+        * Do the appropriate processing for CFB mode decryption.
+        *
+        * @param in the array containing the data to be decrypted.
+        * @param inOff offset into the in array the data starts at.
+        * @param out the array the encrypted data will be copied into.
+        * @param outOff the offset into the out array the output will start at.
+        * @exception DataLengthException if there isn't enough data in in, or
+        * space in out.
+        * @exception InvalidOperationException if the cipher isn't initialised.
+        * @return the number of bytes processed and produced.
+        */
+        public 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");
+            }
+            cipher.ProcessBlock(cfbV, 0, cfbOutV, 0);
+            //
+            // change over the input block.
+            //
+            Array.Copy(cfbV, blockSize, cfbV, 0, cfbV.Length - blockSize);
+            Array.Copy(input, inOff, cfbV, cfbV.Length - blockSize, blockSize);
+            //
+            // XOR the cfbV with the ciphertext producing the plaintext
+            //
+            for (int i = 0; i < blockSize; i++)
+            {
+                outBytes[outOff + i] = (byte)(cfbOutV[i] ^ input[inOff + i]);
+            }
+            return blockSize;
+        }
+        /**
+        * reset the chaining vector back to the IV and reset the underlying
+        * cipher.
+        */
+        public void Reset()
+        {
+            Array.Copy(IV, 0, cfbV, 0, IV.Length);
+            cipher.Reset();
+        }
+    }
+}
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
new file mode 100644
index 000000000..b3016d79c
--- /dev/null
+++ b/Crypto/src/crypto/modes/EAXBlockCipher.cs
@@ -0,0 +1,302 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+	/**
+	* A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and 
+	* Efficiency - by M. Bellare, P. Rogaway, D. Wagner.
+	* 
+	* http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf
+	* 
+	* EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block 
+	* cipher to encrypt and authenticate data. It's on-line (the length of a 
+	* message isn't needed to begin processing it), has good performances, it's
+	* simple and provably secure (provided the underlying block cipher is secure).
+	* 
+	* Of course, this implementations is NOT thread-safe.
+	*/
+	public class EaxBlockCipher
+		: IAeadBlockCipher
+	{
+		private enum Tag : byte { N, H, C };
+
+		private SicBlockCipher cipher;
+
+		private bool forEncryption;
+
+		private int blockSize;
+
+		private IMac mac;
+
+		private byte[] nonceMac;
+		private byte[] associatedTextMac;
+		private byte[] macBlock;
+
+		private int macSize;
+		private byte[] bufBlock;
+		private int bufOff;
+
+		/**
+		* Constructor that accepts an instance of a block cipher engine.
+		*
+		* @param cipher the engine to use
+		*/
+		public EaxBlockCipher(
+			IBlockCipher cipher)
+		{
+			blockSize = cipher.GetBlockSize();
+			mac = new CMac(cipher);
+			macBlock = new byte[blockSize];
+			bufBlock = new byte[blockSize * 2];
+			associatedTextMac = new byte[mac.GetMacSize()];
+			nonceMac = new byte[mac.GetMacSize()];
+			this.cipher = new SicBlockCipher(cipher);
+		}
+
+		public virtual string AlgorithmName
+		{
+			get { return cipher.GetUnderlyingCipher().AlgorithmName + "/EAX"; }
+		}
+
+		public virtual int GetBlockSize()
+		{
+			return cipher.GetBlockSize();
+		}
+
+		public virtual void Init(
+			bool				forEncryption,
+			ICipherParameters	parameters)
+		{
+			this.forEncryption = forEncryption;
+
+			byte[] nonce, associatedText;
+			ICipherParameters keyParam;
+
+			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 = new byte[0];
+				macSize = mac.GetMacSize() / 2;
+				keyParam = param.Parameters;
+			}
+			else
+			{
+				throw new ArgumentException("invalid parameters passed to EAX");
+			}
+
+			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);
+
+			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);
+
+			cipher.Init(true, new ParametersWithIV(keyParam, nonceMac));
+		}
+
+		private void calculateMac()
+		{
+			byte[] outC = new byte[blockSize];
+			mac.DoFinal(outC, 0);
+
+			for (int i = 0; i < macBlock.Length; i++)
+			{
+				macBlock[i] = (byte)(nonceMac[i] ^ associatedTextMac[i] ^ outC[i]);
+			}
+		}
+
+		public virtual void Reset()
+		{
+			Reset(true);
+		}
+
+		private void Reset(
+			bool clearMac)
+		{
+			cipher.Reset();
+			mac.Reset();
+
+			bufOff = 0;
+			Array.Clear(bufBlock, 0, bufBlock.Length);
+
+			if (clearMac)
+			{
+				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	input,
+			byte[]	outBytes,
+			int		outOff)
+		{
+			return process(input, outBytes, outOff);
+		}
+
+		public virtual int ProcessBytes(
+			byte[]	inBytes,
+			int		inOff,
+			int		len,
+			byte[]	outBytes,
+			int		outOff)
+		{
+			int resultLen = 0;
+
+			for (int i = 0; i != len; i++)
+			{
+				resultLen += process(inBytes[inOff + i], outBytes, outOff + resultLen);
+			}
+
+			return resultLen;
+		}
+
+		public virtual int DoFinal(
+			byte[]	outBytes,
+			int		outOff)
+		{
+			int extra = bufOff;
+			byte[] tmp = new byte[bufBlock.Length];
+
+			bufOff = 0;
+
+			if (forEncryption)
+			{
+				cipher.ProcessBlock(bufBlock, 0, tmp, 0);
+				cipher.ProcessBlock(bufBlock, blockSize, tmp, blockSize);
+
+				Array.Copy(tmp, 0, outBytes, outOff, extra);
+
+				mac.BlockUpdate(tmp, 0, extra);
+
+				calculateMac();
+
+				Array.Copy(macBlock, 0, outBytes, outOff + extra, macSize);
+
+				Reset(false);
+
+				return extra + macSize;
+			}
+			else
+			{
+				if (extra > macSize)
+				{
+					mac.BlockUpdate(bufBlock, 0, extra - macSize);
+
+					cipher.ProcessBlock(bufBlock, 0, tmp, 0);
+					cipher.ProcessBlock(bufBlock, blockSize, tmp, blockSize);
+
+					Array.Copy(tmp, 0, outBytes, outOff, extra - macSize);
+				}
+
+				calculateMac();
+
+				if (!verifyMac(bufBlock, extra - macSize))
+					throw new InvalidCipherTextException("mac check in EAX failed");
+
+				Reset(false);
+
+				return extra - macSize;
+			}
+		}
+
+		public virtual byte[] GetMac()
+		{
+			byte[] mac = new byte[macSize];
+
+			Array.Copy(macBlock, 0, mac, 0, macSize);
+
+			return mac;
+		}
+
+		public virtual int GetUpdateOutputSize(
+			int len)
+		{
+			return ((len + bufOff) / blockSize) * blockSize;
+		}
+
+		public virtual int GetOutputSize(
+			int len)
+		{
+			if (forEncryption)
+			{
+				return len + bufOff + macSize;
+			}
+
+			return len + bufOff - macSize;
+		}
+
+		private int process(
+			byte	b,
+			byte[]	outBytes,
+			int		outOff)
+		{
+			bufBlock[bufOff++] = b;
+
+			if (bufOff == bufBlock.Length)
+			{
+				int size;
+
+				if (forEncryption)
+				{
+					size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
+
+					mac.BlockUpdate(outBytes, outOff, blockSize);
+				}
+				else
+				{
+					mac.BlockUpdate(bufBlock, 0, blockSize);
+
+					size = cipher.ProcessBlock(bufBlock, 0, outBytes, outOff);
+				}
+
+				bufOff = blockSize;
+				Array.Copy(bufBlock, blockSize, bufBlock, 0, blockSize);
+
+				return size;
+			}
+
+			return 0;
+		}
+
+		private bool verifyMac(byte[] mac, int off)
+		{
+			for (int i = 0; i < macSize; i++)
+			{
+				if (macBlock[i] != mac[off + i])
+				{
+					return false;
+				}
+			}
+
+			return true;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/modes/GCMBlockCipher.cs b/Crypto/src/crypto/modes/GCMBlockCipher.cs
new file mode 100644
index 000000000..6a3a4463d
--- /dev/null
+++ b/Crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -0,0 +1,400 @@
+using System;
+
+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
diff --git a/Crypto/src/crypto/modes/GOFBBlockCipher.cs b/Crypto/src/crypto/modes/GOFBBlockCipher.cs
new file mode 100644
index 000000000..7db843115
--- /dev/null
+++ b/Crypto/src/crypto/modes/GOFBBlockCipher.cs
@@ -0,0 +1,223 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+	/**
+	* implements the GOST 28147 OFB counter mode (GCTR).
+	*/
+	public class GOfbBlockCipher
+		: IBlockCipher
+	{
+		private byte[]	IV;
+		private byte[]	ofbV;
+		private byte[]	ofbOutV;
+
+		private readonly int			blockSize;
+		private readonly IBlockCipher	cipher;
+
+		bool firstStep = true;
+		int N3;
+		int N4;
+		const int C1 = 16843012; //00000001000000010000000100000100
+		const int C2 = 16843009; //00000001000000010000000100000001
+
+		/**
+		* Basic constructor.
+		*
+		* @param cipher the block cipher to be used as the basis of the
+		* counter mode (must have a 64 bit block size).
+		*/
+		public GOfbBlockCipher(
+			IBlockCipher cipher)
+		{
+			this.cipher = cipher;
+			this.blockSize = cipher.GetBlockSize();
+
+			if (blockSize != 8)
+			{
+				throw new ArgumentException("GCTR only for 64 bit block ciphers");
+			}
+
+			this.IV = new byte[cipher.GetBlockSize()];
+			this.ofbV = new byte[cipher.GetBlockSize()];
+			this.ofbOutV = new byte[cipher.GetBlockSize()];
+		}
+
+		/**
+		* return the underlying block cipher that we are wrapping.
+		*
+		* @return the underlying block cipher that we are wrapping.
+		*/
+		public IBlockCipher GetUnderlyingCipher()
+		{
+			return cipher;
+		}
+
+		/**
+		* Initialise the cipher and, possibly, the initialisation vector (IV).
+		* If an IV isn't passed as part of the parameter, the IV will be all zeros.
+		* An IV which is too short is handled in FIPS compliant fashion.
+		*
+		* @param encrypting if true the cipher is initialised for
+		*  encryption, if false for decryption.
+		* @param parameters the key and other data required by the cipher.
+		* @exception ArgumentException if the parameters argument is inappropriate.
+		*/
+		public void Init(
+			bool				forEncryption, //ignored by this CTR mode
+			ICipherParameters	parameters)
+		{
+			firstStep = true;
+			N3 = 0;
+			N4 = 0;
+
+			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);
+		}
+
+		/**
+		* return the algorithm name and mode.
+		*
+		* @return the name of the underlying algorithm followed by "/GCTR"
+		* and the block size in bits
+		*/
+		public string AlgorithmName
+		{
+			get { return cipher.AlgorithmName + "/GCTR"; }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return true; }
+		}
+
+		/**
+		* return the block size we are operating at (in bytes).
+		*
+		* @return the block size we are operating at (in bytes).
+		*/
+		public int GetBlockSize()
+		{
+			return blockSize;
+		}
+
+		/**
+		* Process one block of input from the array in and write it to
+		* the out array.
+		*
+		* @param in the array containing the input data.
+		* @param inOff offset into the in array the data starts at.
+		* @param out the array the output data will be copied into.
+		* @param outOff the offset into the out array the output will start at.
+		* @exception DataLengthException if there isn't enough data in in, or
+		* space in out.
+		* @exception 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 ((inOff + blockSize) > input.Length)
+			{
+				throw new DataLengthException("input buffer too short");
+			}
+
+			if ((outOff + blockSize) > output.Length)
+			{
+				throw new DataLengthException("output buffer too short");
+			}
+
+			if (firstStep)
+			{
+				firstStep = false;
+				cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
+				N3 = bytesToint(ofbOutV, 0);
+				N4 = bytesToint(ofbOutV, 4);
+			}
+			N3 += C2;
+			N4 += C1;
+			intTobytes(N3, ofbV, 0);
+			intTobytes(N4, ofbV, 4);
+
+			cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
+
+			//
+			// XOR the ofbV with the plaintext producing the cipher text (and
+			// the next input block).
+			//
+			for (int i = 0; i < blockSize; i++)
+			{
+				output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
+			}
+
+			//
+			// change over the input block.
+			//
+			Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
+			Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
+
+			return blockSize;
+		}
+
+		/**
+		* reset the feedback vector back to the IV and reset the underlying
+		* cipher.
+		*/
+		public void Reset()
+		{
+			Array.Copy(IV, 0, ofbV, 0, IV.Length);
+
+			cipher.Reset();
+		}
+
+		//array of bytes to type int
+		private int bytesToint(
+			byte[]  inBytes,
+			int     inOff)
+		{
+			return  (int)((inBytes[inOff + 3] << 24) & 0xff000000) + ((inBytes[inOff + 2] << 16) & 0xff0000) +
+					((inBytes[inOff + 1] << 8) & 0xff00) + (inBytes[inOff] & 0xff);
+		}
+
+		//int to array of bytes
+		private void intTobytes(
+				int     num,
+				byte[]  outBytes,
+				int     outOff)
+		{
+				outBytes[outOff + 3] = (byte)(num >> 24);
+				outBytes[outOff + 2] = (byte)(num >> 16);
+				outBytes[outOff + 1] = (byte)(num >> 8);
+				outBytes[outOff] =     (byte)num;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/modes/IAeadBlockCipher.cs b/Crypto/src/crypto/modes/IAeadBlockCipher.cs
new file mode 100644
index 000000000..ca7dab44c
--- /dev/null
+++ b/Crypto/src/crypto/modes/IAeadBlockCipher.cs
@@ -0,0 +1,90 @@
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+	/// <summary>
+	/// A block cipher mode that includes authenticated encryption with a streaming mode
+	/// and optional associated data.</summary>
+	/// <see cref="AeadParameters"/>
+	public interface IAeadBlockCipher
+	{
+		/// <summary>The name of the algorithm this cipher implements.</summary>
+		string AlgorithmName { get; }
+
+		/// <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>
+		/// <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();
+
+		/**
+		* Encrypt/decrypt a single byte.
+		*
+		* @param input the byte to be processed.
+		* @param outBytes the output buffer the processed byte goes into.
+		* @param outOff the offset into the output byte array the processed data starts at.
+		* @return the number of bytes written to out.
+		* @exception DataLengthException if the output buffer is too small.
+		*/
+		int ProcessByte(byte input, byte[] outBytes, int outOff);
+
+		/**
+		* Process a block of bytes from in putting the result into out.
+		*
+		* @param inBytes 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 outBytes the output buffer the processed bytes go into.
+		* @param outOff the offset into the output byte array the processed data starts at.
+		* @return the number of bytes written to out.
+		* @exception DataLengthException if the output buffer is too small.
+		*/
+		int ProcessBytes(byte[] inBytes, int inOff, int len, byte[] outBytes, int outOff);
+
+		/**
+		* Finish the operation either appending or verifying the MAC at the end of the data.
+		*
+		* @param outBytes space for any resulting output data.
+		* @param outOff offset into out to start copying the data at.
+		* @return number of bytes written into out.
+		* @throws InvalidOperationException if the cipher is in an inappropriate state.
+		* @throws InvalidCipherTextException if the MAC fails to match.
+		*/
+		int DoFinal(byte[] outBytes, int outOff);
+
+		/**
+		* Return the value of the MAC associated with the last stream processed.
+		*
+		* @return MAC for plaintext data.
+		*/
+		byte[] GetMac();
+
+		/**
+		* Return the size of the output buffer required for a ProcessBytes
+		* an input of len bytes.
+		*
+		* @param len the length of the input.
+		* @return the space required to accommodate a call to ProcessBytes
+		* with len bytes of input.
+		*/
+		int GetUpdateOutputSize(int len);
+
+		/**
+		* Return the size of the output buffer required for a ProcessBytes plus a
+		* DoFinal with an input of len bytes.
+		*
+		* @param len the length of the input.
+		* @return the space required to accommodate a call to ProcessBytes and DoFinal
+		* with len bytes of input.
+		*/
+		int GetOutputSize(int len);
+
+		/// <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/modes/OfbBlockCipher.cs b/Crypto/src/crypto/modes/OfbBlockCipher.cs
new file mode 100644
index 000000000..9408a74d4
--- /dev/null
+++ b/Crypto/src/crypto/modes/OfbBlockCipher.cs
@@ -0,0 +1,178 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Modes
+{
+    /**
+    * implements a Output-FeedBack (OFB) mode on top of a simple cipher.
+    */
+    public class OfbBlockCipher
+		: IBlockCipher
+    {
+        private byte[]	IV;
+        private byte[]	ofbV;
+        private byte[]	ofbOutV;
+
+        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 OfbBlockCipher(
+            IBlockCipher cipher,
+            int         blockSize)
+        {
+            this.cipher = cipher;
+            this.blockSize = blockSize / 8;
+
+            this.IV = new byte[cipher.GetBlockSize()];
+            this.ofbV = new byte[cipher.GetBlockSize()];
+            this.ofbOutV = new byte[cipher.GetBlockSize()];
+        }
+
+        /**
+        * return the underlying block cipher that we are wrapping.
+        *
+        * @return the underlying block cipher that we are wrapping.
+        */
+        public IBlockCipher GetUnderlyingCipher()
+        {
+            return cipher;
+        }
+
+        /**
+        * Initialise the cipher and, possibly, the initialisation vector (IV).
+        * If an IV isn't passed as part of the parameter, the IV will be all zeros.
+        * An IV which is too short is handled in FIPS compliant fashion.
+        *
+        * @param 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 void Init(
+            bool				forEncryption, //ignored by this OFB mode
+            ICipherParameters	parameters)
+        {
+			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);
+        }
+
+		/**
+        * return the algorithm name and mode.
+        *
+        * @return the name of the underlying algorithm followed by "/OFB"
+        * and the block size in bits
+        */
+        public string AlgorithmName
+        {
+            get { return cipher.AlgorithmName + "/OFB" + (blockSize * 8); }
+        }
+
+		public bool IsPartialBlockOkay
+		{
+			get { return true; }
+		}
+
+		/**
+        * return the block size we are operating at (in bytes).
+        *
+        * @return the block size we are operating at (in bytes).
+        */
+        public int GetBlockSize()
+        {
+            return blockSize;
+        }
+
+        /**
+        * Process one block of input from the array in and write it to
+        * the out array.
+        *
+        * @param in the array containing the input data.
+        * @param inOff offset into the in array the data starts at.
+        * @param out the array the output data will be copied into.
+        * @param outOff the offset into the out array the output will start at.
+        * @exception DataLengthException if there isn't enough data in in, or
+        * space in out.
+        * @exception 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 ((inOff + blockSize) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+
+            if ((outOff + blockSize) > output.Length)
+            {
+                throw new DataLengthException("output buffer too short");
+            }
+
+            cipher.ProcessBlock(ofbV, 0, ofbOutV, 0);
+
+            //
+            // XOR the ofbV with the plaintext producing the cipher text (and
+            // the next input block).
+            //
+            for (int i = 0; i < blockSize; i++)
+            {
+                output[outOff + i] = (byte)(ofbOutV[i] ^ input[inOff + i]);
+            }
+
+            //
+            // change over the input block.
+            //
+            Array.Copy(ofbV, blockSize, ofbV, 0, ofbV.Length - blockSize);
+            Array.Copy(ofbOutV, 0, ofbV, ofbV.Length - blockSize, blockSize);
+
+            return blockSize;
+        }
+
+        /**
+        * reset the feedback vector back to the IV and reset the underlying
+        * cipher.
+        */
+        public void Reset()
+        {
+            Array.Copy(IV, 0, ofbV, 0, IV.Length);
+
+            cipher.Reset();
+        }
+    }
+
+}
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
new file mode 100644
index 000000000..c45026e82
--- /dev/null
+++ b/Crypto/src/crypto/modes/SicBlockCipher.cs
@@ -0,0 +1,110 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+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;
+
+		/**
+		* 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;
+		}
+
+		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");
+	        }
+		}
+
+		public string AlgorithmName
+		{
+			get { return cipher.AlgorithmName + "/SIC"; }
+		}
+
+		public bool IsPartialBlockOkay
+		{
+			get { return true; }
+		}
+
+		public int GetBlockSize()
+		{
+			return cipher.GetBlockSize();
+		}
+
+		public int ProcessBlock(
+			byte[]	input,
+			int		inOff,
+			byte[]	output,
+			int		outOff)
+		{
+			cipher.ProcessBlock(counter, 0, counterOut, 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]);
+			}
+
+			// Increment the counter
+			int j = counter.Length;
+			while (--j >= 0 && ++counter[j] == 0)
+			{
+			}
+
+			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
new file mode 100644
index 000000000..4076de990
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/BasicGcmMultiplier.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+	public class BasicGcmMultiplier
+		: IGcmMultiplier
+	{
+		private byte[] H;
+
+		public void Init(byte[] H)
+		{
+			this.H = (byte[])H.Clone();
+		}
+
+		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
new file mode 100644
index 000000000..8da125641
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -0,0 +1,149 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+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)
+		{
+//			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];
+			}
+		}
+	}
+}
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
new file mode 100644
index 000000000..9425a3d9d
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/Tables1kGcmExponentiator.cs
@@ -0,0 +1,44 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+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][];
+
+		public void Init(byte[] x)
+		{
+			lookupPowX2[0] = GcmUtilities.OneAsBytes();
+			lookupPowX2[1] = Arrays.Clone(x); 
+
+			for (int i = 2; i != 64; ++i)
+			{
+				byte[] tmp = Arrays.Clone(lookupPowX2[i - 1]);
+				GcmUtilities.Multiply(tmp, tmp);
+				lookupPowX2[i] = tmp;
+			}
+		}
+
+		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;
+			}
+
+			Array.Copy(y, 0, output, 0, 16);
+		}
+	}
+}
diff --git a/Crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs b/Crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs
new file mode 100644
index 000000000..f089dfe8d
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/Tables64kGcmMultiplier.cs
@@ -0,0 +1,64 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Modes.Gcm
+{
+	public class Tables64kGcmMultiplier
+		: IGcmMultiplier
+	{
+		private readonly uint[][][] M = new uint[16][][];
+
+		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;
+					}
+				}
+
+				if (++i == 16) return;
+
+				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
new file mode 100644
index 000000000..91d58fab8
--- /dev/null
+++ b/Crypto/src/crypto/modes/gcm/Tables8kGcmMultiplier.cs
@@ -0,0 +1,90 @@
+using System;
+
+using Org.BouncyCastle.Crypto.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);
+
+			for (int j = 4; j >= 1; j >>= 1)
+			{
+				uint[] tmp = (uint[])M[1][j + j].Clone();
+				GcmUtilities.MultiplyP(tmp);
+				M[1][j] = tmp;
+			}
+
+			{
+				uint[] tmp = (uint[])M[1][1].Clone();
+				GcmUtilities.MultiplyP(tmp);
+				M[0][8] = tmp;
+			}
+
+			for (int j = 4; 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 < 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;
+					}
+				}
+
+				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
new file mode 100644
index 000000000..06b2f5c38
--- /dev/null
+++ b/Crypto/src/crypto/parameters/AEADParameters.cs
@@ -0,0 +1,53 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	public class AeadParameters
+		: ICipherParameters
+	{
+		private readonly byte[] associatedText;
+		private readonly byte[] nonce;
+		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
+		 * @param associatedText associated text, if any
+		 */
+		public AeadParameters(
+			KeyParameter	key,
+			int				macSize,
+			byte[]			nonce,
+			byte[]			associatedText)
+		{
+			this.key = key;
+			this.nonce = nonce;
+			this.macSize = macSize;
+			this.associatedText = associatedText;
+		}
+
+		public virtual KeyParameter Key
+		{
+			get { return key; }
+		}
+
+		public virtual int MacSize
+		{
+			get { return macSize; }
+		}
+
+		public virtual byte[] GetAssociatedText()
+		{
+			return associatedText;
+		}
+
+		public virtual byte[] GetNonce()
+		{
+			return nonce;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/parameters/CcmParameters.cs b/Crypto/src/crypto/parameters/CcmParameters.cs
new file mode 100644
index 000000000..8dc981e1f
--- /dev/null
+++ b/Crypto/src/crypto/parameters/CcmParameters.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class CcmParameters
+        : AeadParameters 
+    {
+		/**
+		 * Base constructor.
+		 * 
+		 * @param key key to be used by underlying cipher
+		 * @param macSize macSize in bits
+		 * @param nonce nonce to be used
+		 * @param associatedText associated text, if any
+		 */
+		public CcmParameters(
+			KeyParameter	key,
+			int				macSize,
+			byte[]			nonce,
+			byte[]			associatedText)
+			: base(key, macSize, nonce, associatedText)
+		{
+		}
+	}
+}
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/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
new file mode 100644
index 000000000..b9cdc4a79
--- /dev/null
+++ b/Crypto/src/crypto/parameters/DsaValidationParameters.cs
@@ -0,0 +1,59 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class DsaValidationParameters
+    {
+        private readonly byte[] seed;
+        private readonly int counter;
+
+		public DsaValidationParameters(
+            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;
+
+			DsaValidationParameters other = obj as DsaValidationParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+		}
+
+		protected bool Equals(
+			DsaValidationParameters other)
+		{
+			return counter == other.counter
+				&& Arrays.AreEqual(seed, other.seed);
+		}
+
+		public override int GetHashCode()
+        {
+			return counter.GetHashCode() ^ Arrays.GetHashCode(seed);
+		}
+    }
+}
diff --git a/Crypto/src/crypto/parameters/ECDomainParameters.cs b/Crypto/src/crypto/parameters/ECDomainParameters.cs
new file mode 100644
index 000000000..c6a3e4e72
--- /dev/null
+++ b/Crypto/src/crypto/parameters/ECDomainParameters.cs
@@ -0,0 +1,116 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ECDomainParameters
+    {
+        internal ECCurve     curve;
+        internal byte[]      seed;
+        internal ECPoint     g;
+        internal BigInteger  n;
+        internal BigInteger  h;
+
+		public ECDomainParameters(
+            ECCurve     curve,
+            ECPoint     g,
+            BigInteger  n)
+			: this(curve, g, n, BigInteger.One)
+        {
+        }
+
+        public ECDomainParameters(
+            ECCurve     curve,
+            ECPoint     g,
+            BigInteger  n,
+            BigInteger  h)
+			: this(curve, g, n, h, null)
+		{
+        }
+
+		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;
+            this.n = n;
+            this.h = h;
+            this.seed = Arrays.Clone(seed);
+        }
+
+		public ECCurve Curve
+        {
+            get { return curve; }
+        }
+
+        public ECPoint G
+        {
+            get { return g; }
+        }
+
+        public BigInteger N
+        {
+            get { return n; }
+        }
+
+        public BigInteger H
+        {
+            get { return h; }
+        }
+
+        public byte[] GetSeed()
+        {
+			return Arrays.Clone(seed);
+        }
+
+		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(
+			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()
+        {
+            return curve.GetHashCode()
+				^	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
new file mode 100644
index 000000000..4d4622ced
--- /dev/null
+++ b/Crypto/src/crypto/parameters/ECKeyParameters.cs
@@ -0,0 +1,145 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public abstract class ECKeyParameters
+		: AsymmetricKeyParameter
+    {
+		private readonly string algorithm;
+		private readonly ECDomainParameters parameters;
+		private readonly DerObjectIdentifier publicKeyParamSet;
+
+		protected ECKeyParameters(
+			string				algorithm,
+            bool				isPrivate,
+            ECDomainParameters	parameters)
+			: 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 (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
+        {
+			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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/parameters/ECPrivateKeyParameters.cs b/Crypto/src/crypto/parameters/ECPrivateKeyParameters.cs
new file mode 100644
index 000000000..e6352d5d1
--- /dev/null
+++ b/Crypto/src/crypto/parameters/ECPrivateKeyParameters.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ECPrivateKeyParameters
+		: 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)
+        {
+			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()
+        {
+            return d.GetHashCode() ^ base.GetHashCode();
+        }
+	}
+}
diff --git a/Crypto/src/crypto/parameters/ECPublicKeyParameters.cs b/Crypto/src/crypto/parameters/ECPublicKeyParameters.cs
new file mode 100644
index 000000000..9e71c2a25
--- /dev/null
+++ b/Crypto/src/crypto/parameters/ECPublicKeyParameters.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ECPublicKeyParameters
+		: 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)
+        {
+			if (q == null)
+				throw new ArgumentNullException("q");
+
+			this.q = q;
+		}
+
+		public ECPublicKeyParameters(
+			string				algorithm,
+			ECPoint				q,
+			DerObjectIdentifier publicKeyParamSet)
+			: base(algorithm, false, publicKeyParamSet)
+        {
+			if (q == null)
+				throw new ArgumentNullException("q");
+
+			this.q = q;
+		}
+
+		public ECPoint Q
+        {
+			get { return q; }
+        }
+
+		public override bool Equals(object obj)
+        {
+			if (obj == this)
+				return true;
+
+			ECPublicKeyParameters other = obj as ECPublicKeyParameters;
+
+			if (other == null)
+				return false;
+
+			return Equals(other);
+        }
+
+		protected bool Equals(
+			ECPublicKeyParameters other)
+		{
+			return q.Equals(other.q) && base.Equals(other);
+		}
+
+		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
new file mode 100644
index 000000000..42a0454a1
--- /dev/null
+++ b/Crypto/src/crypto/parameters/NaccacheSternPrivateKeyParameters.cs
@@ -0,0 +1,79 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+	/**
+	 * Private key parameters for NaccacheStern cipher. For details on this cipher,
+	 * please see
+	 *
+	 * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
+	 */
+	public class NaccacheSternPrivateKeyParameters : NaccacheSternKeyParameters
+	{
+		private readonly BigInteger phiN;
+		private readonly IList smallPrimes;
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public NaccacheSternPrivateKeyParameters(
+            BigInteger g,
+            BigInteger n,
+            int lowerSigmaBound,
+            ArrayList smallPrimes,
+            BigInteger phiN)
+            : base(true, g, n, lowerSigmaBound)
+        {
+            this.smallPrimes = smallPrimes;
+            this.phiN = phiN;
+        }
+#endif
+
+		/**
+		 * Constructs a NaccacheSternPrivateKey
+		 *
+		 * @param g
+		 *            the public enryption parameter g
+		 * @param n
+		 *            the public modulus n = p*q
+		 * @param lowerSigmaBound
+		 *            the public lower sigma bound up to which data can be encrypted
+		 * @param smallPrimes
+		 *            the small primes, of which sigma is constructed in the right
+		 *            order
+		 * @param phi_n
+		 *            the private modulus phi(n) = (p-1)(q-1)
+		 */
+		public NaccacheSternPrivateKeyParameters(
+			BigInteger	g,
+			BigInteger	n,
+			int			lowerSigmaBound,
+			IList       smallPrimes,
+			BigInteger	phiN)
+			: base(true, g, n, lowerSigmaBound)
+		{
+			this.smallPrimes = smallPrimes;
+			this.phiN = phiN;
+		}
+
+		public BigInteger PhiN
+		{
+			get { return phiN; }
+		}
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete("Use 'SmallPrimesList' instead")]
+        public ArrayList SmallPrimes
+		{
+			get { return new ArrayList(smallPrimes); }
+		}
+#endif
+
+        public IList SmallPrimesList
+        {
+            get { return smallPrimes; }
+        }
+    }
+}
diff --git a/Crypto/src/crypto/parameters/ParametersWithIV.cs b/Crypto/src/crypto/parameters/ParametersWithIV.cs
new file mode 100644
index 000000000..e00abce58
--- /dev/null
+++ b/Crypto/src/crypto/parameters/ParametersWithIV.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Parameters
+{
+    public class ParametersWithIV
+		: ICipherParameters
+    {
+		private readonly ICipherParameters	parameters;
+		private readonly byte[]				iv;
+
+		public ParametersWithIV(
+            ICipherParameters	parameters,
+            byte[]				iv)
+			: this(parameters, iv, 0, iv.Length)
+		{
+		}
+
+		public ParametersWithIV(
+            ICipherParameters	parameters,
+            byte[]				iv,
+            int					ivOff,
+            int					ivLen)
+        {
+			if (parameters == null)
+				throw new ArgumentNullException("parameters");
+			if (iv == null)
+				throw new ArgumentNullException("iv");
+
+			this.parameters = parameters;
+			this.iv = new byte[ivLen];
+            Array.Copy(iv, ivOff, this.iv, 0, ivLen);
+        }
+
+		public byte[] GetIV()
+        {
+			return (byte[]) iv.Clone();
+        }
+
+		public ICipherParameters Parameters
+        {
+            get { return parameters; }
+        }
+    }
+}
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/prng/CryptoApiRandomGenerator.cs b/Crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
new file mode 100644
index 000000000..9e9e29cf1
--- /dev/null
+++ b/Crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
@@ -0,0 +1,66 @@
+#if !(NETCF_1_0 || PORTABLE)
+
+using System;
+using System.Security.Cryptography;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+	/// <summary>
+	/// Uses Microsoft's RNGCryptoServiceProvider
+	/// </summary>
+	public class CryptoApiRandomGenerator
+		: IRandomGenerator
+	{
+		private readonly RandomNumberGenerator rndProv;
+
+		public CryptoApiRandomGenerator()
+			: this(new RNGCryptoServiceProvider())
+		{
+		}
+
+		public CryptoApiRandomGenerator(RandomNumberGenerator rng)
+		{
+			this.rndProv = rng;
+		}
+
+		#region IRandomGenerator Members
+
+		public virtual void AddSeedMaterial(byte[] seed)
+		{
+			// We don't care about the seed
+		}
+
+		public virtual void AddSeedMaterial(long seed)
+		{
+			// We don't care about the seed
+		}
+
+		public virtual void NextBytes(byte[] bytes)
+		{
+			rndProv.GetBytes(bytes);
+		}
+
+		public virtual void NextBytes(byte[] bytes, int start, int len)
+		{
+			if (start < 0)
+				throw new ArgumentException("Start offset cannot be negative", "start");
+			if (bytes.Length < (start + len))
+				throw new ArgumentException("Byte array too small for requested offset and length");
+
+			if (bytes.Length == len && start == 0) 
+			{
+				NextBytes(bytes);
+			}
+			else 
+			{
+				byte[] tmpBuf = new byte[len];
+				rndProv.GetBytes(tmpBuf);
+				Array.Copy(tmpBuf, 0, bytes, start, len);
+			}
+		}
+
+		#endregion
+	}
+}
+
+#endif
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
new file mode 100644
index 000000000..9f918ea6e
--- /dev/null
+++ b/Crypto/src/crypto/prng/ThreadedSeedGenerator.cs
@@ -0,0 +1,99 @@
+using System;
+using System.Threading;
+
+namespace Org.BouncyCastle.Crypto.Prng
+{
+	/**
+	 * A thread based seed generator - one source of randomness.
+	 * <p>
+	 * Based on an idea from Marcus Lippert.
+	 * </p>
+	 */
+	public class ThreadedSeedGenerator
+	{
+		private class SeedGenerator
+		{
+#if NETCF_1_0
+			// No volatile keyword, but all fields implicitly volatile anyway
+			private int		counter = 0;
+			private bool	stop = false;
+#else
+			private volatile int	counter = 0;
+			private volatile bool	stop = false;
+#endif
+
+			private void Run(object ignored)
+			{
+				while (!this.stop)
+				{
+					this.counter++;
+				}
+			}
+
+			public byte[] GenerateSeed(
+				int		numBytes,
+				bool	fast)
+			{
+				this.counter = 0;
+				this.stop = false;
+
+				byte[] result = new byte[numBytes];
+				int last = 0;
+				int end = fast ? numBytes : numBytes * 8;
+
+				ThreadPool.QueueUserWorkItem(new WaitCallback(Run));
+
+				for (int i = 0; i < end; i++)
+				{
+                    var waitEvent = new ManualResetEvent(false);
+
+					while (this.counter == last)
+					{
+						try
+						{
+                            waitEvent.WaitOne(1);
+						}
+						catch (Exception)
+						{
+							// ignore
+						}
+					}
+
+					last = this.counter;
+
+					if (fast)
+					{
+						result[i] = (byte) last;
+					}
+					else
+					{
+						int bytepos = i / 8;
+						result[bytepos] = (byte) ((result[bytepos] << 1) | (last & 1));
+					}
+				}
+
+				this.stop = true;
+
+				return result;
+			}
+		}
+
+		/**
+		 * Generate seed bytes. Set fast to false for best quality.
+		 * <p>
+		 * If fast is set to true, the code should be round about 8 times faster when
+		 * generating a long sequence of random bytes. 20 bytes of random values using
+		 * the fast mode take less than half a second on a Nokia e70. If fast is set to false,
+		 * it takes round about 2500 ms.
+		 * </p>
+		 * @param numBytes the number of bytes to generate
+		 * @param fast true if fast mode should be used
+		 */
+		public byte[] GenerateSeed(
+			int		numBytes,
+			bool	fast)
+		{
+			return new SeedGenerator().GenerateSeed(numBytes, fast);
+		}
+	}
+}
diff --git a/Crypto/src/crypto/prng/VMPCRandomGenerator.cs b/Crypto/src/crypto/prng/VMPCRandomGenerator.cs
new file mode 100644
index 000000000..2ab079999
--- /dev/null
+++ b/Crypto/src/crypto/prng/VMPCRandomGenerator.cs
@@ -0,0 +1,115 @@
+namespace Org.BouncyCastle.Crypto.Prng
+{
+	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>Value generated in the same way as <c>P</c>.</remarks>
+		private byte s = (byte) 0xbe;
+
+		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(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 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);
+				}
+			}
+		}
+	}
+}
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
new file mode 100644
index 000000000..419b1972e
--- /dev/null
+++ b/Crypto/src/crypto/signers/DsaSigner.cs
@@ -0,0 +1,136 @@
+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;
+
+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);
+		}
+	}
+}
diff --git a/Crypto/src/crypto/signers/ECDsaSigner.cs b/Crypto/src/crypto/signers/ECDsaSigner.cs
new file mode 100644
index 000000000..4254e5590
--- /dev/null
+++ b/Crypto/src/crypto/signers/ECDsaSigner.cs
@@ -0,0 +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;
+
+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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/signers/ECGOST3410Signer.cs b/Crypto/src/crypto/signers/ECGOST3410Signer.cs
new file mode 100644
index 000000000..d68b83f67
--- /dev/null
+++ b/Crypto/src/crypto/signers/ECGOST3410Signer.cs
@@ -0,0 +1,154 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+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);
+		}
+	}
+}
diff --git a/Crypto/src/crypto/signers/ECNRSigner.cs b/Crypto/src/crypto/signers/ECNRSigner.cs
new file mode 100644
index 000000000..63865d731
--- /dev/null
+++ b/Crypto/src/crypto/signers/ECNRSigner.cs
@@ -0,0 +1,186 @@
+using System;
+
+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;
+
+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);
+		}
+	}
+}
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/Iso9796d2PssSigner.cs b/Crypto/src/crypto/signers/Iso9796d2PssSigner.cs
new file mode 100644
index 000000000..48cd719e9
--- /dev/null
+++ b/Crypto/src/crypto/signers/Iso9796d2PssSigner.cs
@@ -0,0 +1,576 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/signers/Iso9796d2Signer.cs b/Crypto/src/crypto/signers/Iso9796d2Signer.cs
new file mode 100644
index 000000000..8ff87e8ee
--- /dev/null
+++ b/Crypto/src/crypto/signers/Iso9796d2Signer.cs
@@ -0,0 +1,557 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+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;
+		}
+	}
+}
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/RsaDigestSigner.cs b/Crypto/src/crypto/signers/RsaDigestSigner.cs
new file mode 100644
index 000000000..f57bfc83d
--- /dev/null
+++ b/Crypto/src/crypto/signers/RsaDigestSigner.cs
@@ -0,0 +1,228 @@
+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.TeleTrust;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    public class RsaDigestSigner
+		: ISigner
+    {
+        private readonly IAsymmetricBlockCipher rsaEngine = new Pkcs1Encoding(new RsaBlindedEngine());
+        private readonly AlgorithmIdentifier algId;
+		private readonly IDigest digest;
+		private bool forSigning;
+
+		private static readonly IDictionary oidMap = Platform.CreateHashtable();
+
+		/// <summary>
+        /// Load oid table.
+        /// </summary>
+        static RsaDigestSigner()
+        {
+            oidMap["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
+            oidMap["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
+            oidMap["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
+
+            oidMap["SHA-1"] = X509ObjectIdentifiers.IdSha1;
+            oidMap["SHA-224"] = NistObjectIdentifiers.IdSha224;
+            oidMap["SHA-256"] = NistObjectIdentifiers.IdSha256;
+            oidMap["SHA-384"] = NistObjectIdentifiers.IdSha384;
+            oidMap["SHA-512"] = NistObjectIdentifiers.IdSha512;
+
+            oidMap["MD2"] = PkcsObjectIdentifiers.MD2;
+            oidMap["MD4"] = PkcsObjectIdentifiers.MD4;
+            oidMap["MD5"] = PkcsObjectIdentifiers.MD5;
+        }
+
+		public RsaDigestSigner(
+			IDigest digest)
+        {
+            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 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)
+        {
+            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();
+
+            rsaEngine.Init(forSigning, parameters);
+        }
+
+        /**
+         * update the internal digest with the byte b
+         */
+        public void Update(
+			byte input)
+        {
+            digest.Update(input);
+        }
+
+        /**
+         * update the internal digest with the byte array in
+         */
+        public void 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("RsaDigestSigner not initialised for signature generation.");
+
+			byte[] hash = new byte[digest.GetDigestSize()];
+            digest.DoFinal(hash, 0);
+
+			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)
+        {
+			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;
+        }
+
+        public void Reset()
+        {
+            digest.Reset();
+        }
+
+		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);
+
+			return dInfo.GetDerEncoded();
+		}
+    }
+}
diff --git a/Crypto/src/crypto/tls/AlertDescription.cs b/Crypto/src/crypto/tls/AlertDescription.cs
new file mode 100644
index 000000000..e1229a4a3
--- /dev/null
+++ b/Crypto/src/crypto/tls/AlertDescription.cs
@@ -0,0 +1,47 @@
+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,
+	}
+}
diff --git a/Crypto/src/crypto/tls/AlertLevel.cs b/Crypto/src/crypto/tls/AlertLevel.cs
new file mode 100644
index 000000000..afb04308b
--- /dev/null
+++ b/Crypto/src/crypto/tls/AlertLevel.cs
@@ -0,0 +1,11 @@
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	/// <summary>
+	/// RFC 2246 7.2
+	/// </summary>
+    public enum AlertLevel : byte
+	{
+	    warning = 1,
+	    fatal = 2,
+	}
+}
diff --git a/Crypto/src/crypto/tls/AlwaysValidVerifyer.cs b/Crypto/src/crypto/tls/AlwaysValidVerifyer.cs
new file mode 100644
index 000000000..e26c6fc3f
--- /dev/null
+++ b/Crypto/src/crypto/tls/AlwaysValidVerifyer.cs
@@ -0,0 +1,24 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	/// <remarks>
+	/// A certificate verifyer, that will always return true.
+	/// <pre>
+	/// DO NOT USE THIS FILE UNLESS YOU KNOW EXACTLY WHAT YOU ARE DOING.
+	/// </pre>
+	/// </remarks>
+	[Obsolete("Perform certificate verification in TlsAuthentication implementation")]
+	public class AlwaysValidVerifyer
+		: ICertificateVerifyer
+	{
+		/// <summary>Return true.</summary>
+		public bool IsValid(
+			X509CertificateStructure[] certs)
+		{
+			return true;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/ByteQueue.cs b/Crypto/src/crypto/tls/ByteQueue.cs
new file mode 100644
index 000000000..96062402b
--- /dev/null
+++ b/Crypto/src/crypto/tls/ByteQueue.cs
@@ -0,0 +1,125 @@
+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;
+		}
+
+		/**
+		 * The initial size for our buffer.
+		 */
+		private const int InitBufSize = 1024;
+
+		/**
+		 * The buffer where we store our data.
+		 */
+		private byte[] databuf = new byte[ByteQueue.InitBufSize];
+
+		/**
+		 * 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;
+
+		/// <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);
+		}
+
+		/// <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;
+		}
+
+		/// <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);
+			}
+
+			/*
+			* Skip the data.
+			*/
+			available -= i;
+			skipped += i;
+
+			/*
+			* 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;
+			}
+		}
+
+		/// <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/Certificate.cs b/Crypto/src/crypto/tls/Certificate.cs
new file mode 100644
index 000000000..e4df041e2
--- /dev/null
+++ b/Crypto/src/crypto/tls/Certificate.cs
@@ -0,0 +1,111 @@
+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
+{
+	/**
+	* 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)
+            {
+                certs[i] = (X509CertificateStructure)tmp[i];
+            }
+			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; }
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/CertificateRequest.cs b/Crypto/src/crypto/tls/CertificateRequest.cs
new file mode 100644
index 000000000..49d8ba6fb
--- /dev/null
+++ b/Crypto/src/crypto/tls/CertificateRequest.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections;
+
+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
diff --git a/Crypto/src/crypto/tls/CipherSuite.cs b/Crypto/src/crypto/tls/CipherSuite.cs
new file mode 100644
index 000000000..6e1f7a545
--- /dev/null
+++ b/Crypto/src/crypto/tls/CipherSuite.cs
@@ -0,0 +1,136 @@
+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,
+	}
+}
diff --git a/Crypto/src/crypto/tls/ClientCertificateType.cs b/Crypto/src/crypto/tls/ClientCertificateType.cs
new file mode 100644
index 000000000..58f5d4276
--- /dev/null
+++ b/Crypto/src/crypto/tls/ClientCertificateType.cs
@@ -0,0 +1,20 @@
+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,
+
+		/*
+		 * RFC 4492 5.5
+		 */
+		ecdsa_sign = 64,
+		rsa_fixed_ecdh = 65,
+		ecdsa_fixed_ecdh = 66,
+	}
+}
\ No newline at end of file
diff --git a/Crypto/src/crypto/tls/CombinedHash.cs b/Crypto/src/crypto/tls/CombinedHash.cs
new file mode 100644
index 000000000..59ad87a7b
--- /dev/null
+++ b/Crypto/src/crypto/tls/CombinedHash.cs
@@ -0,0 +1,82 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+
+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();
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/CompressionMethod.cs b/Crypto/src/crypto/tls/CompressionMethod.cs
new file mode 100644
index 000000000..4a127a63e
--- /dev/null
+++ b/Crypto/src/crypto/tls/CompressionMethod.cs
@@ -0,0 +1,20 @@
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	/// <summary>
+	/// RFC 2246 6.1
+	/// </summary>
+    public enum CompressionMethod : byte
+	{
+		NULL = 0,
+
+		/*
+		 * RFC 3749 2
+		 */
+		DEFLATE = 1
+
+		/*
+		 * Values from 224 decimal (0xE0) through 255 decimal (0xFF)
+		 * inclusive are reserved for private use.
+		 */
+	}
+}
diff --git a/Crypto/src/crypto/tls/ContentType.cs b/Crypto/src/crypto/tls/ContentType.cs
new file mode 100644
index 000000000..a664e3a38
--- /dev/null
+++ b/Crypto/src/crypto/tls/ContentType.cs
@@ -0,0 +1,13 @@
+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,
+	}
+}
diff --git a/Crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs b/Crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
new file mode 100644
index 000000000..2dfe526d1
--- /dev/null
+++ b/Crypto/src/crypto/tls/DefaultTlsAgreementCredentials.cs
@@ -0,0 +1,67 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public class DefaultTlsAgreementCredentials
+		: TlsAgreementCredentials
+	{
+		protected Certificate clientCert;
+		protected AsymmetricKeyParameter clientPrivateKey;
+
+		protected IBasicAgreement basicAgreement;
+
+		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");
+			}
+
+			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");
+			}
+
+			this.clientCert = clientCertificate;
+			this.clientPrivateKey = clientPrivateKey;
+		}
+
+		public virtual Certificate Certificate
+		{
+			get { return clientCert; }
+		}
+
+		public virtual byte[] GenerateAgreement(AsymmetricKeyParameter serverPublicKey)
+		{
+			basicAgreement.Init(clientPrivateKey);
+			BigInteger agreementValue = basicAgreement.CalculateAgreement(serverPublicKey);
+			return BigIntegers.AsUnsignedByteArray(agreementValue);
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/DefaultTlsCipherFactory.cs b/Crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
new file mode 100644
index 000000000..53e3438d9
--- /dev/null
+++ b/Crypto/src/crypto/tls/DefaultTlsCipherFactory.cs
@@ -0,0 +1,73 @@
+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);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/DefaultTlsClient.cs b/Crypto/src/crypto/tls/DefaultTlsClient.cs
new file mode 100644
index 000000000..c5b59a06b
--- /dev/null
+++ b/Crypto/src/crypto/tls/DefaultTlsClient.cs
@@ -0,0 +1,259 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+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()
+        {
+			/*
+			 * To offer DEFLATE compression, override this method:
+			 *     return new CompressionMethod[] { CompressionMethod.DEFLATE, CompressionMethod.NULL };
+			 */
+
+            return new CompressionMethod[] { CompressionMethod.NULL };
+        }
+
+        public virtual IDictionary GetClientExtensions()
+		{
+			return 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_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)
+        {
+            return new TlsECDHKeyExchange(context, keyExchange);
+        }
+
+        protected virtual TlsKeyExchange CreateECDheKeyExchange(KeyExchangeAlgorithm keyExchange)
+        {
+            return new TlsECDheKeyExchange(context, keyExchange);
+        }
+
+        protected virtual TlsKeyExchange CreateRsaKeyExchange()
+		{
+			return new TlsRsaKeyExchange(context);
+		}
+    }
+}
diff --git a/Crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs b/Crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
new file mode 100644
index 000000000..23d607d85
--- /dev/null
+++ b/Crypto/src/crypto/tls/DefaultTlsSignerCredentials.cs
@@ -0,0 +1,76 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public class DefaultTlsSignerCredentials
+		: TlsSignerCredentials
+	{
+		protected TlsClientContext context;
+		protected Certificate clientCert;
+		protected AsymmetricKeyParameter clientPrivateKey;
+
+		protected TlsSigner clientSigner;
+
+		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");
+			}
+
+			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");
+			}
+
+			this.context = context;
+			this.clientCert = clientCertificate;
+			this.clientPrivateKey = clientPrivateKey;
+		}
+
+		public virtual Certificate Certificate
+		{
+			get { return clientCert; }
+		}
+
+		public virtual byte[] GenerateCertificateSignature(byte[] md5andsha1)
+		{
+			try
+			{
+				return clientSigner.CalculateRawSignature(context.SecureRandom, clientPrivateKey, md5andsha1);
+			}
+			catch (CryptoException)
+			{
+				throw new TlsFatalAlert(AlertDescription.internal_error);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/DigestAlgorithm.cs b/Crypto/src/crypto/tls/DigestAlgorithm.cs
new file mode 100644
index 000000000..cede6b7f8
--- /dev/null
+++ b/Crypto/src/crypto/tls/DigestAlgorithm.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public enum DigestAlgorithm
+	{
+		/*
+		 * Note that the values here are implementation-specific and arbitrary.
+		 * It is recommended not to depend on the particular values (e.g. serialization).
+		 */
+		NULL,
+		MD5,
+		SHA,
+
+		/*
+		 * RFC 5289
+		 */
+		SHA256,
+		SHA384,
+	}
+}
diff --git a/Crypto/src/crypto/tls/ECCurveType.cs b/Crypto/src/crypto/tls/ECCurveType.cs
new file mode 100644
index 000000000..15d5d7b42
--- /dev/null
+++ b/Crypto/src/crypto/tls/ECCurveType.cs
@@ -0,0 +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,
+
+		/**
+		 * Indicates the elliptic curve domain parameters are conveyed verbosely, and the
+		 * underlying finite field is a characteristic-2 field.
+		 */
+		explicit_char2 = 2,
+
+		/**
+		 * Indicates that a named curve is used. This option SHOULD be used when applicable.
+		 */
+		named_curve = 3,
+
+		/*
+		 * 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
new file mode 100644
index 000000000..4e0dd0067
--- /dev/null
+++ b/Crypto/src/crypto/tls/ECPointFormat.cs
@@ -0,0 +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,
+
+		/*
+		 * reserved (248..255)
+		 */
+	}
+}
diff --git a/Crypto/src/crypto/tls/EncryptionAlgorithm.cs b/Crypto/src/crypto/tls/EncryptionAlgorithm.cs
new file mode 100644
index 000000000..79d3b63b5
--- /dev/null
+++ b/Crypto/src/crypto/tls/EncryptionAlgorithm.cs
@@ -0,0 +1,32 @@
+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,
+	}
+}
diff --git a/Crypto/src/crypto/tls/ExtensionType.cs b/Crypto/src/crypto/tls/ExtensionType.cs
new file mode 100644
index 000000000..f00e34e3f
--- /dev/null
+++ b/Crypto/src/crypto/tls/ExtensionType.cs
@@ -0,0 +1,31 @@
+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,
+	}
+}
diff --git a/Crypto/src/crypto/tls/HandshakeType.cs b/Crypto/src/crypto/tls/HandshakeType.cs
new file mode 100644
index 000000000..deedb1f84
--- /dev/null
+++ b/Crypto/src/crypto/tls/HandshakeType.cs
@@ -0,0 +1,19 @@
+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,
+	}
+}
diff --git a/Crypto/src/crypto/tls/ICertificateVerifyer.cs b/Crypto/src/crypto/tls/ICertificateVerifyer.cs
new file mode 100644
index 000000000..df5ea51d7
--- /dev/null
+++ b/Crypto/src/crypto/tls/ICertificateVerifyer.cs
@@ -0,0 +1,18 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	/// <remarks>
+	/// This should be implemented by any class which can find out, if a given
+	/// certificate chain is being accepted by an client.
+	/// </remarks>
+	[Obsolete("Perform certificate verification in TlsAuthentication implementation")]
+	public interface ICertificateVerifyer
+	{
+		/// <param name="certs">The certs, which are part of the chain.</param>
+		/// <returns>True, if the chain is accepted, false otherwise</returns>
+		bool IsValid(X509CertificateStructure[] certs);
+	}
+}
diff --git a/Crypto/src/crypto/tls/KeyExchangeAlgorithm.cs b/Crypto/src/crypto/tls/KeyExchangeAlgorithm.cs
new file mode 100644
index 000000000..3fdbeb2a6
--- /dev/null
+++ b/Crypto/src/crypto/tls/KeyExchangeAlgorithm.cs
@@ -0,0 +1,36 @@
+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,
+	}
+}
diff --git a/Crypto/src/crypto/tls/LegacyTlsAuthentication.cs b/Crypto/src/crypto/tls/LegacyTlsAuthentication.cs
new file mode 100644
index 000000000..395f94208
--- /dev/null
+++ b/Crypto/src/crypto/tls/LegacyTlsAuthentication.cs
@@ -0,0 +1,30 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	/// <summary>
+	/// A temporary class to wrap old CertificateVerifyer stuff for new TlsAuthentication.
+	/// </summary>
+	[Obsolete]
+	public class LegacyTlsAuthentication
+		: TlsAuthentication
+	{
+		protected ICertificateVerifyer verifyer;
+
+		public LegacyTlsAuthentication(ICertificateVerifyer verifyer)
+		{
+			this.verifyer = verifyer;
+		}
+
+		public virtual void NotifyServerCertificate(Certificate serverCertificate)
+		{
+			if (!this.verifyer.IsValid(serverCertificate.GetCerts()))
+				throw new TlsFatalAlert(AlertDescription.user_canceled);
+		}
+
+		public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest)
+		{
+			return null;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/LegacyTlsClient.cs b/Crypto/src/crypto/tls/LegacyTlsClient.cs
new file mode 100644
index 000000000..fbb9a732e
--- /dev/null
+++ b/Crypto/src/crypto/tls/LegacyTlsClient.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	/// <summary>
+	/// A temporary class to use LegacyTlsAuthentication 
+	/// </summary>
+	[Obsolete]
+	public class LegacyTlsClient
+		: DefaultTlsClient
+	{
+		[Obsolete]
+		protected ICertificateVerifyer verifyer;
+
+		[Obsolete]
+		public LegacyTlsClient(ICertificateVerifyer verifyer)
+		{
+			this.verifyer = verifyer;
+		}
+
+		public override TlsAuthentication GetAuthentication()
+		{
+			return new LegacyTlsAuthentication(verifyer);
+		}
+	}
+}
\ No newline at end of file
diff --git a/Crypto/src/crypto/tls/NamedCurve.cs b/Crypto/src/crypto/tls/NamedCurve.cs
new file mode 100644
index 000000000..c8ee189aa
--- /dev/null
+++ b/Crypto/src/crypto/tls/NamedCurve.cs
@@ -0,0 +1,72 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.X9;
+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,
+
+		/*
+		 * reserved (0xFE00..0xFEFF)
+		 */
+
+		arbitrary_explicit_prime_curves = 0xFF01,
+		arbitrary_explicit_char2_curves = 0xFF02,
+	}
+
+	internal class NamedCurveHelper
+	{
+	    internal static ECDomainParameters GetECParameters(NamedCurve namedCurve)
+	    {
+            if (!Enum.IsDefined(typeof(NamedCurve), namedCurve))
+                return null;
+
+            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());
+	    }
+	}
+}
diff --git a/Crypto/src/crypto/tls/PskTlsClient.cs b/Crypto/src/crypto/tls/PskTlsClient.cs
new file mode 100644
index 000000000..16975e713
--- /dev/null
+++ b/Crypto/src/crypto/tls/PskTlsClient.cs
@@ -0,0 +1,182 @@
+using System;
+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);
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/RecordStream.cs b/Crypto/src/crypto/tls/RecordStream.cs
new file mode 100644
index 000000000..e18894b4e
--- /dev/null
+++ b/Crypto/src/crypto/tls/RecordStream.cs
@@ -0,0 +1,166 @@
+using System;
+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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/SecurityParameters.cs b/Crypto/src/crypto/tls/SecurityParameters.cs
new file mode 100644
index 000000000..9ed3969eb
--- /dev/null
+++ b/Crypto/src/crypto/tls/SecurityParameters.cs
@@ -0,0 +1,26 @@
+using System;
+
+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; }
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/SrpTlsClient.cs b/Crypto/src/crypto/tls/SrpTlsClient.cs
new file mode 100644
index 000000000..6c2638bb3
--- /dev/null
+++ b/Crypto/src/crypto/tls/SrpTlsClient.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections;
+using System.IO;
+
+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 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);
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/Ssl3Mac.cs b/Crypto/src/crypto/tls/Ssl3Mac.cs
new file mode 100644
index 000000000..b2f3f309e
--- /dev/null
+++ b/Crypto/src/crypto/tls/Ssl3Mac.cs
@@ -0,0 +1,114 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsAgreementCredentials.cs b/Crypto/src/crypto/tls/TlsAgreementCredentials.cs
new file mode 100644
index 000000000..46ee4f90e
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsAgreementCredentials.cs
@@ -0,0 +1,11 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public interface TlsAgreementCredentials : TlsCredentials
+	{
+		/// <exception cref="IOException"></exception>
+		byte[] GenerateAgreement(AsymmetricKeyParameter serverPublicKey);
+	}
+}
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
new file mode 100644
index 000000000..ef7be1913
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsBlockCipher.cs
@@ -0,0 +1,248 @@
+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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsCipher.cs b/Crypto/src/crypto/tls/TlsCipher.cs
new file mode 100644
index 000000000..22c769d82
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsCipher.cs
@@ -0,0 +1,14 @@
+using System;
+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);
+
+		/// <exception cref="IOException"></exception>
+		byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len);
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsCipherFactory.cs b/Crypto/src/crypto/tls/TlsCipherFactory.cs
new file mode 100644
index 000000000..0756603f4
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsCipherFactory.cs
@@ -0,0 +1,12 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public interface TlsCipherFactory
+	{
+		/// <exception cref="IOException"></exception>
+		TlsCipher CreateCipher(TlsClientContext context, EncryptionAlgorithm encryptionAlgorithm,
+			DigestAlgorithm digestAlgorithm);
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsClient.cs b/Crypto/src/crypto/tls/TlsClient.cs
new file mode 100644
index 000000000..eceaa3cd3
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsClient.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Collections;
+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();
+
+        /// <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.
+        /// </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);
+
+        /// <summary>
+        /// Report the compression method that was selected by the server.
+        /// </summary>
+        /// <remarks>
+        /// The protocol handler validates this value against the offered compression methods
+        /// <seealso cref="GetCompressionMethods"/>
+        /// </remarks>
+        /// <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();
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsClientContext.cs b/Crypto/src/crypto/tls/TlsClientContext.cs
new file mode 100644
index 000000000..dbb10aa76
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsClientContext.cs
@@ -0,0 +1,15 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public interface TlsClientContext
+	{
+		SecureRandom SecureRandom { get; }
+
+		SecurityParameters SecurityParameters { get; }
+
+		object UserObject { get; set; }
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsClientContextImpl.cs b/Crypto/src/crypto/tls/TlsClientContextImpl.cs
new file mode 100644
index 000000000..9d5dee232
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsClientContextImpl.cs
@@ -0,0 +1,37 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	internal class TlsClientContextImpl
+		: TlsClientContext
+	{
+		private readonly SecureRandom secureRandom;
+		private readonly SecurityParameters 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; }
+		}
+	}
+}
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/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
new file mode 100644
index 000000000..40ac416e0
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsDHKeyExchange.cs
@@ -0,0 +1,201 @@
+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;
+
+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);
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsDHUtilities.cs b/Crypto/src/crypto/tls/TlsDHUtilities.cs
new file mode 100644
index 000000000..733749ea1
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsDHUtilities.cs
@@ -0,0 +1,70 @@
+using System;
+using System.IO;
+
+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
+{
+	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
diff --git a/Crypto/src/crypto/tls/TlsDeflateCompression.cs b/Crypto/src/crypto/tls/TlsDeflateCompression.cs
new file mode 100644
index 000000000..146c961c7
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsDeflateCompression.cs
@@ -0,0 +1,45 @@
+using System;
+using System.IO;
+
+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;
+			}
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsDheKeyExchange.cs b/Crypto/src/crypto/tls/TlsDheKeyExchange.cs
new file mode 100644
index 000000000..edadaeb38
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsDheKeyExchange.cs
@@ -0,0 +1,56 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsDsaSigner.cs b/Crypto/src/crypto/tls/TlsDsaSigner.cs
new file mode 100644
index 000000000..27d7b1f91
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsDsaSigner.cs
@@ -0,0 +1,51 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+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();
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsDssSigner.cs b/Crypto/src/crypto/tls/TlsDssSigner.cs
new file mode 100644
index 000000000..c6f1abcec
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsDssSigner.cs
@@ -0,0 +1,21 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	internal class TlsDssSigner
+		: TlsDsaSigner
+	{
+		public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
+		{
+			return publicKey is DsaPublicKeyParameters;
+		}
+
+	    protected override IDsa CreateDsaImpl()
+	    {
+			return new DsaSigner();
+	    }
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsECDHKeyExchange.cs b/Crypto/src/crypto/tls/TlsECDHKeyExchange.cs
new file mode 100644
index 000000000..83983ba47
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsECDHKeyExchange.cs
@@ -0,0 +1,230 @@
+using System;
+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
+    {
+		protected TlsClientContext context;
+		protected KeyExchangeAlgorithm keyExchange;
+		protected TlsSigner tlsSigner;
+
+		protected AsymmetricKeyParameter serverPublicKey;
+		protected ECPublicKeyParameters ecAgreeServerPublicKey;
+		protected TlsAgreementCredentials agreementCredentials;
+		protected ECPrivateKeyParameters ecAgreeClientPrivateKey = null;
+
+		internal TlsECDHKeyExchange(TlsClientContext context, KeyExchangeAlgorithm keyExchange)
+        {
+			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;
+        }
+
+        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.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
+            /*
+            * 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()
+        {
+            // do nothing
+        }
+
+        public virtual void ProcessServerKeyExchange(Stream input)
+        {
+            throw new TlsFatalAlert(AlertDescription.unexpected_message);
+        }
+
+		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)
+        {
+			if (agreementCredentials == null)
+			{
+				GenerateEphemeralClientKeyExchange(ecAgreeServerPublicKey.Parameters, output);
+			}
+        }
+
+        public virtual byte[] GeneratePremasterSecret()
+        {
+			if (agreementCredentials != null)
+			{
+				return agreementCredentials.GenerateAgreement(ecAgreeServerPublicKey);
+			}
+
+			return CalculateECDHBasicAgreement(ecAgreeServerPublicKey, ecAgreeClientPrivateKey);
+        }
+
+		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;
+		}
+    }
+}
diff --git a/Crypto/src/crypto/tls/TlsECDheKeyExchange.cs b/Crypto/src/crypto/tls/TlsECDheKeyExchange.cs
new file mode 100644
index 000000000..5516154ce
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsECDheKeyExchange.cs
@@ -0,0 +1,110 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math.EC;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    /**
+    * ECDHE key exchange (see RFC 4492)
+    */
+    internal class TlsECDheKeyExchange : TlsECDHKeyExchange
+    {
+        internal TlsECDheKeyExchange(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);
+
+            ECCurveType curveType = (ECCurveType)TlsUtilities.ReadUint8(sigIn);
+            ECDomainParameters curve_params;
+
+            //  Currently, we only support named curves
+            if (curveType == ECCurveType.named_curve)
+            {
+                NamedCurve namedCurve = (NamedCurve)TlsUtilities.ReadUint16(sigIn);
+
+                // TODO Check namedCurve is one we offered?
+
+                curve_params = NamedCurveHelper.GetECParameters(namedCurve);
+            }
+            else
+            {
+                // TODO Add support for explicit curve parameters (read from sigIn)
+
+                throw new TlsFatalAlert(AlertDescription.handshake_failure);
+            }
+
+            byte[] publicBytes = TlsUtilities.ReadOpaque8(sigIn);
+
+            byte[] sigByte = TlsUtilities.ReadOpaque16(input);
+            if (!signer.VerifySignature(sigByte))
+            {
+                throw new TlsFatalAlert(AlertDescription.bad_certificate);
+            }
+
+            // TODO Check curve_params not null
+
+            ECPoint Q = curve_params.Curve.DecodePoint(publicBytes);
+
+			this.ecAgreeServerPublicKey = ValidateECPublicKey(new ECPublicKeyParameters(Q, curve_params));
+        }
+		
+		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)
+        {
+            ISigner signer = tlsSigner.CreateVerifyer(this.serverPublicKey);
+            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
new file mode 100644
index 000000000..3c30fdc0c
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsECDsaSigner.cs
@@ -0,0 +1,21 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	internal class TlsECDsaSigner
+		: TlsDsaSigner
+	{
+		public override bool IsValidPublicKey(AsymmetricKeyParameter publicKey)
+		{
+			return publicKey is ECPublicKeyParameters;
+		}
+
+		protected override IDsa CreateDsaImpl()
+		{
+			return new ECDsaSigner();
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsException.cs b/Crypto/src/crypto/tls/TlsException.cs
new file mode 100644
index 000000000..fa3e73273
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public class TlsException : Exception
+	{
+		public TlsException() : base() { }
+		public TlsException(string message) : base(message) { }
+		public TlsException(string message, Exception exception) : base(message, exception) { }
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsFatalAlert.cs b/Crypto/src/crypto/tls/TlsFatalAlert.cs
new file mode 100644
index 000000000..0a9cc6f3a
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsFatalAlert.cs
@@ -0,0 +1,21 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public class TlsFatalAlert
+		: IOException
+	{
+		private readonly AlertDescription alertDescription;
+
+		public TlsFatalAlert(AlertDescription alertDescription)
+		{
+			this.alertDescription = alertDescription;
+		}
+
+		public AlertDescription AlertDescription
+		{
+			get { return alertDescription; }
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsKeyExchange.cs b/Crypto/src/crypto/tls/TlsKeyExchange.cs
new file mode 100644
index 000000000..5102edbec
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsKeyExchange.cs
@@ -0,0 +1,38 @@
+using System;
+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();
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsMac.cs b/Crypto/src/crypto/tls/TlsMac.cs
new file mode 100644
index 000000000..0e58b89dc
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsMac.cs
@@ -0,0 +1,106 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+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);
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsNullCipher.cs b/Crypto/src/crypto/tls/TlsNullCipher.cs
new file mode 100644
index 000000000..b76f76d9c
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsNullCipher.cs
@@ -0,0 +1,28 @@
+using System;
+
+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;
+		}
+	}
+}
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/TlsProtocolHandler.cs b/Crypto/src/crypto/tls/TlsProtocolHandler.cs
new file mode 100644
index 000000000..6d2b0b144
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsProtocolHandler.cs
@@ -0,0 +1,1259 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Agreement.Srp;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Prng;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+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)
+        {
+            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)
+        {
+            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
new file mode 100644
index 000000000..226153a97
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsPskKeyExchange.cs
@@ -0,0 +1,149 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+
+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];
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsRsaKeyExchange.cs b/Crypto/src/crypto/tls/TlsRsaKeyExchange.cs
new file mode 100644
index 000000000..4538a2a81
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsRsaKeyExchange.cs
@@ -0,0 +1,165 @@
+using System;
+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;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	/// <summary>
+	/// TLS 1.0 RSA key exchange.
+	/// </summary>
+	internal class TlsRsaKeyExchange
+		: TlsKeyExchange
+	{
+		protected TlsClientContext context;
+
+		protected AsymmetricKeyParameter serverPublicKey = null;
+
+        protected RsaKeyParameters rsaServerPublicKey = 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));
+//	    }
+
+        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/TlsRsaSigner.cs b/Crypto/src/crypto/tls/TlsRsaSigner.cs
new file mode 100644
index 000000000..a50ff9558
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsRsaSigner.cs
@@ -0,0 +1,53 @@
+using System;
+
+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.Security;
+
+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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsRsaUtilities.cs b/Crypto/src/crypto/tls/TlsRsaUtilities.cs
new file mode 100644
index 000000000..4450ba452
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsRsaUtilities.cs
@@ -0,0 +1,42 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Encodings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Security;
+
+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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsSigner.cs b/Crypto/src/crypto/tls/TlsSigner.cs
new file mode 100644
index 000000000..e59b90705
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsSigner.cs
@@ -0,0 +1,18 @@
+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);
+
+		ISigner CreateSigner(SecureRandom random, AsymmetricKeyParameter privateKey);
+		ISigner CreateVerifyer(AsymmetricKeyParameter publicKey);
+
+		bool IsValidPublicKey(AsymmetricKeyParameter publicKey);
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsSignerCredentials.cs b/Crypto/src/crypto/tls/TlsSignerCredentials.cs
new file mode 100644
index 000000000..2adb06c26
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsSignerCredentials.cs
@@ -0,0 +1,11 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	public interface TlsSignerCredentials : TlsCredentials
+	{
+		/// <exception cref="IOException"></exception>
+		byte[] GenerateCertificateSignature(byte[] md5andsha1);
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsSrpKeyExchange.cs b/Crypto/src/crypto/tls/TlsSrpKeyExchange.cs
new file mode 100644
index 000000000..852aace41
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsSrpKeyExchange.cs
@@ -0,0 +1,203 @@
+using System;
+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;
+
+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;
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsStream.cs b/Crypto/src/crypto/tls/TlsStream.cs
new file mode 100644
index 000000000..e3d05686b
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsStream.cs
@@ -0,0 +1,89 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+	internal class TlsStream
+		: Stream
+	{
+		private readonly TlsProtocolHandler handler;
+
+		internal TlsStream(
+			TlsProtocolHandler handler)
+		{
+			this.handler = handler;
+		}
+
+		public override bool CanRead
+		{
+			get { return !handler.IsClosed; }
+		}
+
+		public override bool CanSeek
+		{
+			get { return false; }
+		}
+
+		public override bool CanWrite
+		{
+			get { return !handler.IsClosed; }
+		}
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                handler.Close();
+            }
+        }
+
+		public override void Flush()
+		{
+			handler.Flush();
+		}
+
+        public override long Length
+		{
+			get { throw new NotSupportedException(); }
+		}
+
+		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 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 void SetLength(long value)
+		{
+			throw new NotSupportedException();
+		}
+
+		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);
+		}
+	}
+}
diff --git a/Crypto/src/crypto/tls/TlsUtilities.cs b/Crypto/src/crypto/tls/TlsUtilities.cs
new file mode 100644
index 000000000..0e2452689
--- /dev/null
+++ b/Crypto/src/crypto/tls/TlsUtilities.cs
@@ -0,0 +1,286 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Parameters;
+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);
+                    //}
+				}
+			}
+		}
+	}
+}
diff --git a/Crypto/src/crypto/util/Pack.cs b/Crypto/src/crypto/util/Pack.cs
new file mode 100644
index 000000000..67c939ad5
--- /dev/null
+++ b/Crypto/src/crypto/util/Pack.cs
@@ -0,0 +1,219 @@
+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);
+	    }
+	}
+}
diff --git a/Crypto/src/math/BigInteger.cs b/Crypto/src/math/BigInteger.cs
new file mode 100644
index 000000000..d52c0f83c
--- /dev/null
+++ b/Crypto/src/math/BigInteger.cs
@@ -0,0 +1,3141 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.Globalization;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Math
+{
+#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE)
+	[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
+//						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)
+				{
+//					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)
+//			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);
+//			return SolovayStrassenTest(certainty, random);
+
+//			bool rbTest = RabinMillerTest(certainty, random);
+//			bool ssTest = SolovayStrassenTest(certainty, random);
+//
+//			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;
+		}
+
+//		private bool SolovayStrassenTest(
+//			int		certainty,
+//			Random	random)
+//		{
+//			Debug.Assert(certainty > 0);
+//			Debug.Assert(CompareTo(Two) > 0);
+//			Debug.Assert(TestBit(0));
+//
+//			BigInteger n = this;
+//			BigInteger nMinusOne = n.Subtract(One);
+//			BigInteger e = nMinusOne.ShiftRight(1);
+//
+//			do
+//			{
+//				BigInteger a;
+//				do
+//				{
+//					a = new BigInteger(nBitLength, random);
+//				}
+//				// NB: Spec says 0 < x < n, but 1 is trivial
+//				while (a.CompareTo(One) <= 0 || a.CompareTo(n) >= 0);
+//
+//
+//				// TODO Check this is redundant given the way Jacobi() works?
+////				if (!a.Gcd(n).Equals(One))
+////					return false;
+//
+//				int x = Jacobi(a, n);
+//
+//				if (x == 0)
+//					return false;
+//
+//				BigInteger check = a.ModPow(e, n);
+//
+//				if (x == 1 && !check.Equals(One))
+//					return false;
+//
+//				if (x == -1 && !check.Equals(nMinusOne))
+//					return false;
+//
+//				--certainty;
+//			}
+//			while (certainty > 0);
+//
+//			return true;
+//		}
+//
+//		private static int Jacobi(
+//			BigInteger	a,
+//			BigInteger	b)
+//		{
+//			Debug.Assert(a.sign >= 0);
+//			Debug.Assert(b.sign > 0);
+//			Debug.Assert(b.TestBit(0));
+//			Debug.Assert(a.CompareTo(b) < 0);
+//
+//			int totalS = 1;
+//			for (;;)
+//			{
+//				if (a.sign == 0)
+//					return 0;
+//
+//				if (a.Equals(One))
+//					break;
+//
+//				int e = a.GetLowestSetBit();
+//
+//				int bLsw = b.magnitude[b.magnitude.Length - 1];
+//				if ((e & 1) != 0 && ((bLsw & 7) == 3 || (bLsw & 7) == 5))
+//					totalS = -totalS;
+//
+//				// TODO Confirm this is faster than later a1.Equals(One) test
+//				if (a.BitLength == e + 1)
+//					break;
+//				BigInteger a1 = a.ShiftRight(e);
+////				if (a1.Equals(One))
+////					break;
+//
+//				int a1Lsw = a1.magnitude[a1.magnitude.Length - 1];
+//				if ((bLsw & 3) == 3 && (a1Lsw & 3) == 3)
+//					totalS = -totalS;
+//
+////				a = b.Mod(a1);
+//				a = b.Remainder(a1);
+//				b = a1;
+//			}
+//			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
+//			// "Fast Key Exchange with Elliptic Curve Systems" R.Schoeppel
+//			if (m.TestBit(0))
+//			{
+//				//The Almost Inverse Algorithm
+//				int k = 0;
+//				BigInteger B = One, C = Zero, F = this, G = m, tmp;
+//
+//				for (;;)
+//				{
+//					// While F is even, do F=F/u, C=C*u, k=k+1.
+//					int zeroes = F.GetLowestSetBit();
+//					if (zeroes > 0)
+//					{
+//						F = F.ShiftRight(zeroes);
+//						C = C.ShiftLeft(zeroes);
+//						k += zeroes;
+//					}
+//
+//					// If F = 1, then return B,k.
+//					if (F.Equals(One))
+//					{
+//						BigInteger half = m.Add(One).ShiftRight(1);
+//						BigInteger halfK = half.ModPow(BigInteger.ValueOf(k), m);
+//						return B.Multiply(halfK).Mod(m);
+//					}
+//
+//					if (F.CompareTo(G) < 0)
+//					{
+//						tmp = G; G = F; F = tmp;
+//						tmp = B; B = C; C = tmp;
+//					}
+//
+//					F = F.Add(G);
+//					B = B.Add(C);
+//				}
+//			}
+
+            BigInteger x;
+            BigInteger gcd = ExtEuclid(this.Mod(m), m, out x);
+
+			if (!gcd.Equals(One))
+				throw new ArithmeticException("Numbers not relatively prime.");
+
+			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;
+            //}
+            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
+//			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);
+		}
+
+        public BigInteger ShiftRight(
+			int n)
+		{
+			if (n == 0)
+				return this;
+
+			if (n < 0)
+				return ShiftLeft(-n);
+
+			if (n >= BitLength)
+				return (this.sign < 0 ? One.Negate() : Zero);
+
+//			int[] res = (int[]) this.magnitude.Clone();
+//
+//			ShiftRightInPlace(0, res, n);
+//
+//			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;
+
+//				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
+                for (int i = S.Count - 1; i >= 0; --i)
+                {
+                    sb.Append((string)S[i]);
+                }
+			}
+
+			string s = sb.ToString();
+
+			Debug.Assert(s.Length > 0);
+
+			// Strip leading zeros. (We know this number is not all zeroes though)
+			if (s[0] == '0')
+			{
+				int nonZeroPos = 0;
+				while (s[++nonZeroPos] == '0') {}
+
+				s = s.Substring(nonZeroPos);
+			}
+
+			if (sign == -1)
+			{
+				s = "-" + s;
+			}
+
+			return 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);
+
+//			// 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);
+		}
+	}
+}
diff --git a/Crypto/src/math/ec/ECAlgorithms.cs b/Crypto/src/math/ec/ECAlgorithms.cs
new file mode 100644
index 000000000..be4fd1b14
--- /dev/null
+++ b/Crypto/src/math/ec/ECAlgorithms.cs
@@ -0,0 +1,93 @@
+using System;
+
+using Org.BouncyCastle.Math;
+
+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;
+		}
+	}
+}
diff --git a/Crypto/src/math/ec/ECCurve.cs b/Crypto/src/math/ec/ECCurve.cs
new file mode 100644
index 000000000..4dd5e74e2
--- /dev/null
+++ b/Crypto/src/math/ec/ECCurve.cs
@@ -0,0 +1,661 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Math.EC.Abc;
+
+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
+    {
+        private readonly BigInteger q;
+		private readonly FpPoint infinity;
+
+		public FpCurve(BigInteger q, BigInteger a, BigInteger b)
+        {
+            this.q = q;
+            this.a = FromBigInteger(a);
+            this.b = FromBigInteger(b);
+			this.infinity = new FpPoint(this, null, null);
+        }
+
+		public BigInteger Q
+        {
+			get { return q; }
+        }
+
+		public override ECPoint Infinity
+		{
+			get { return infinity; }
+		}
+
+		public override int FieldSize
+		{
+			get { return q.BitLength; }
+		}
+
+		public override ECFieldElement FromBigInteger(BigInteger x)
+        {
+            return new FpFieldElement(this.q, x);
+        }
+
+		public override ECPoint CreatePoint(
+			BigInteger	X1,
+			BigInteger	Y1,
+			bool		withCompression)
+		{
+			// TODO Validation of X1, Y1?
+			return new FpPoint(
+				this,
+				FromBigInteger(X1),
+				FromBigInteger(Y1),
+				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();
+
+			//
+			// 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");
+
+			BigInteger betaValue = beta.ToBigInteger();
+			int bit0 = betaValue.TestBit(0) ? 1 : 0;
+
+			if (bit0 != yTilde)
+			{
+				// Use the other root
+				beta = FromBigInteger(q.Subtract(betaValue));
+			}
+
+			return new FpPoint(this, x, beta, true);
+		}
+
+		public override bool Equals(
+            object obj)
+        {
+            if (obj == this)
+                return true;
+
+			FpCurve other = obj as FpCurve;
+
+			if (other == null)
+                return false;
+
+			return Equals(other);
+        }
+
+		protected bool Equals(
+			FpCurve other)
+		{
+			return base.Equals(other) && q.Equals(other.q);
+		}
+
+		public override int GetHashCode()
+        {
+            return base.GetHashCode() ^ q.GetHashCode();
+        }
+    }
+
+	/**
+     * 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
+    {
+        /**
+         * The exponent <code>m</code> of <code>F<sub>2<sup>m</sup></sub></code>.
+         */
+        private readonly 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 readonly 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 readonly 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 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)
+                throw new ArgumentException("k1 must be > 0");
+
+			if (k2 == 0)
+            {
+                if (k3 != 0)
+                    throw new ArgumentException("k3 must be 0 if k2 == 0");
+            }
+            else
+            {
+                if (k2 <= k1)
+                    throw new ArgumentException("k2 must be > k1");
+
+				if (k3 <= k2)
+                    throw new ArgumentException("k3 must be > k2");
+            }
+
+			this.a = FromBigInteger(a);
+            this.b = FromBigInteger(b);
+        }
+
+		public override ECPoint Infinity
+		{
+			get { return infinity; }
+		}
+
+		public override int FieldSize
+		{
+			get { return m; }
+		}
+
+		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);
+		}
+
+		/**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         *
+         * @param beta
+         *            The value to solve the qradratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement solveQuadradicEquation(ECFieldElement beta)
+        {
+            if (beta.ToBigInteger().SignValue == 0)
+            {
+                return FromBigInteger(BigInteger.Zero);
+            }
+
+			ECFieldElement z = null;
+            ECFieldElement gamma = FromBigInteger(BigInteger.Zero);
+
+			while (gamma.ToBigInteger().SignValue == 0)
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(m, new Random()));
+				z = FromBigInteger(BigInteger.Zero);
+
+				ECFieldElement w = beta;
+                for (int i = 1; i <= m - 1; i++)
+                {
+					ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (w.ToBigInteger().SignValue != 0)
+                {
+                    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);
+        }
+
+		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;
+        }
+
+		public int M
+        {
+			get { return m; }
+        }
+
+		/**
+         * Return true if curve uses a Trinomial basis.
+         *
+         * @return true if curve Trinomial, false otherwise.
+         */
+        public bool IsTrinomial()
+        {
+            return k2 == 0 && k3 == 0;
+        }
+
+		public int K1
+        {
+			get { return k1; }
+        }
+
+		public int K2
+        {
+			get { return k2; }
+        }
+
+		public int K3
+        {
+			get { return k3; }
+        }
+
+		public BigInteger N
+		{
+			get { return n; }
+		}
+
+		public BigInteger H
+		{
+			get { return h; }
+		}
+	}
+}
diff --git a/Crypto/src/math/ec/ECFieldElement.cs b/Crypto/src/math/ec/ECFieldElement.cs
new file mode 100644
index 000000000..5235c6c0e
--- /dev/null
+++ b/Crypto/src/math/ec/ECFieldElement.cs
@@ -0,0 +1,1253 @@
+using System;
+using System.Diagnostics;
+
+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();
+		}
+	}
+}
diff --git a/Crypto/src/math/ec/ECPoint.cs b/Crypto/src/math/ec/ECPoint.cs
new file mode 100644
index 000000000..f95f09974
--- /dev/null
+++ b/Crypto/src/math/ec/ECPoint.cs
@@ -0,0 +1,567 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Asn1.X9;
+
+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");
+
+//			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();
+						}
+					}
+				}
+			}
+		}
+	}
+}
diff --git a/Crypto/src/math/ec/IntArray.cs b/Crypto/src/math/ec/IntArray.cs
new file mode 100644
index 000000000..1089966a8
--- /dev/null
+++ b/Crypto/src/math/ec/IntArray.cs
@@ -0,0 +1,485 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Math.EC
+{
+	internal class IntArray
+    {
+        // TODO make m fixed for the IntArray, and hence compute T once and for all
+
+		// TODO Use uint's internally?
+		private int[] m_ints;
+
+		public IntArray(int intLen)
+		{
+			m_ints = new int[intLen];
+		}
+
+		private IntArray(int[] ints)
+		{
+			m_ints = ints;
+		}
+
+		public IntArray(BigInteger bigInt)
+			: this(bigInt, 0)
+		{
+		}
+
+		public IntArray(BigInteger bigInt, int minIntLen)
+		{
+			if (bigInt.SignValue == -1)
+				throw new ArgumentException("Only positive Integers allowed", "bigint");
+
+			if (bigInt.SignValue == 0)
+			{
+				m_ints = new int[] { 0 };
+				return;
+			}
+
+			byte[] barr = bigInt.ToByteArrayUnsigned();
+			int barrLen = barr.Length;
+
+			int intLen = (barrLen + 3) / 4;
+			m_ints = new int[System.Math.Max(intLen, minIntLen)];
+
+			int rem = barrLen % 4;
+			int barrI = 0;
+
+			if (0 < rem)
+			{
+				int temp = (int) barr[barrI++];
+				while (barrI < rem)
+				{
+					temp = temp << 8 | (int) barr[barrI++];
+				}
+				m_ints[--intLen] = temp;
+			}
+
+			while (intLen > 0)
+			{
+				int temp = (int) barr[barrI++];
+				for (int i = 1; i < 4; i++)
+				{
+					temp = temp << 8 | (int) barr[barrI++];
+				}
+				m_ints[--intLen] = temp;
+			}
+		}
+
+		public int GetUsedLength()
+		{
+			int highestIntPos = m_ints.Length;
+
+			if (highestIntPos < 1)
+				return 0;
+
+			// Check if first element will act as sentinel
+			if (m_ints[0] != 0)
+			{
+				while (m_ints[--highestIntPos] == 0)
+				{
+				}
+				return highestIntPos + 1;
+			}
+
+			do
+			{
+				if (m_ints[--highestIntPos] != 0)
+				{
+					return highestIntPos + 1;
+				}
+			}
+			while (highestIntPos > 0);
+
+			return 0;
+		}
+
+		public int BitLength
+		{
+			get
+			{
+				// JDK 1.5: see Integer.numberOfLeadingZeros()
+				int intLen = GetUsedLength();
+				if (intLen == 0)
+					return 0;
+
+				int last = intLen - 1;
+				uint highest = (uint) m_ints[last];
+				int bits = (last << 5) + 1;
+
+				// A couple of binary search steps
+				if (highest > 0x0000ffff)
+				{
+					if (highest > 0x00ffffff)
+					{
+						bits += 24;
+						highest >>= 24;
+					}
+					else
+					{
+						bits += 16;
+						highest >>= 16;
+					}
+				}
+				else if (highest > 0x000000ff)
+				{
+					bits += 8;
+					highest >>= 8;
+				}
+
+				while (highest > 1)
+				{
+					++bits;
+					highest >>= 1;
+				}
+
+				return bits;
+			}
+		}
+
+		private int[] resizedInts(int newLen)
+		{
+			int[] newInts = new int[newLen];
+			int oldLen = m_ints.Length;
+			int copyLen = oldLen < newLen ? oldLen : newLen;
+			Array.Copy(m_ints, 0, newInts, 0, copyLen);
+			return newInts;
+		}
+
+		public BigInteger ToBigInteger()
+		{
+			int usedLen = GetUsedLength();
+			if (usedLen == 0)
+			{
+				return BigInteger.Zero;
+			}
+
+			int highestInt = m_ints[usedLen - 1];
+			byte[] temp = new byte[4];
+			int barrI = 0;
+			bool trailingZeroBytesDone = false;
+			for (int j = 3; j >= 0; j--)
+			{
+				byte thisByte = (byte)((int)((uint) highestInt >> (8 * j)));
+				if (trailingZeroBytesDone || (thisByte != 0))
+				{
+					trailingZeroBytesDone = true;
+					temp[barrI++] = thisByte;
+				}
+			}
+
+			int barrLen = 4 * (usedLen - 1) + barrI;
+			byte[] barr = new byte[barrLen];
+			for (int j = 0; j < barrI; j++)
+			{
+				barr[j] = temp[j];
+			}
+			// Highest value int is done now
+
+			for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+			{
+				for (int j = 3; j >= 0; j--)
+				{
+					barr[barrI++] = (byte)((int)((uint)m_ints[iarrJ] >> (8 * j)));
+				}
+			}
+			return new BigInteger(1, barr);
+		}
+
+		public void ShiftLeft()
+		{
+			int usedLen = GetUsedLength();
+			if (usedLen == 0)
+			{
+				return;
+			}
+			if (m_ints[usedLen - 1] < 0)
+			{
+				// highest bit of highest used byte is set, so shifting left will
+				// make the IntArray one byte longer
+				usedLen++;
+				if (usedLen > m_ints.Length)
+				{
+					// make the m_ints one byte longer, because we need one more
+					// byte which is not available in m_ints
+					m_ints = resizedInts(m_ints.Length + 1);
+				}
+			}
+
+			bool carry = false;
+			for (int i = 0; i < usedLen; i++)
+			{
+				// nextCarry is true if highest bit is set
+				bool nextCarry = m_ints[i] < 0;
+				m_ints[i] <<= 1;
+				if (carry)
+				{
+					// set lowest bit
+					m_ints[i] |= 1;
+				}
+				carry = nextCarry;
+			}
+		}
+
+		public IntArray ShiftLeft(int n)
+		{
+			int usedLen = GetUsedLength();
+			if (usedLen == 0)
+			{
+				return this;
+			}
+
+			if (n == 0)
+			{
+				return this;
+			}
+
+			if (n > 31)
+			{
+				throw new ArgumentException("shiftLeft() for max 31 bits "
+					+ ", " + n + "bit shift is not possible", "n");
+			}
+
+			int[] newInts = new int[usedLen + 1];
+
+			int nm32 = 32 - n;
+			newInts[0] = m_ints[0] << n;
+			for (int i = 1; i < usedLen; i++)
+			{
+				newInts[i] = (m_ints[i] << n) | (int)((uint)m_ints[i - 1] >> nm32);
+			}
+			newInts[usedLen] = (int)((uint)m_ints[usedLen - 1] >> nm32);
+
+			return new IntArray(newInts);
+		}
+
+		public void AddShifted(IntArray other, int shift)
+		{
+			int usedLenOther = other.GetUsedLength();
+			int newMinUsedLen = usedLenOther + shift;
+			if (newMinUsedLen > m_ints.Length)
+			{
+				m_ints = resizedInts(newMinUsedLen);
+				//Console.WriteLine("Resize required");
+			}
+
+			for (int i = 0; i < usedLenOther; i++)
+			{
+				m_ints[i + shift] ^= other.m_ints[i];
+			}
+		}
+
+		public int Length
+		{
+			get { return m_ints.Length; }
+		}
+
+		public bool TestBit(int n)
+		{
+			// theInt = n / 32
+			int theInt = n >> 5;
+			// theBit = n % 32
+			int theBit = n & 0x1F;
+			int tester = 1 << theBit;
+			return ((m_ints[theInt] & tester) != 0);
+		}
+
+		public void FlipBit(int n)
+		{
+			// theInt = n / 32
+			int theInt = n >> 5;
+			// theBit = n % 32
+			int theBit = n & 0x1F;
+			int flipper = 1 << theBit;
+			m_ints[theInt] ^= flipper;
+		}
+
+		public void SetBit(int n)
+		{
+			// theInt = n / 32
+			int theInt = n >> 5;
+			// theBit = n % 32
+			int theBit = n & 0x1F;
+			int setter = 1 << theBit;
+			m_ints[theInt] |= setter;
+		}
+
+		public IntArray Multiply(IntArray other, int m)
+		{
+			// Lenght of c is 2m bits rounded up to the next int (32 bit)
+			int t = (m + 31) >> 5;
+			if (m_ints.Length < t)
+			{
+				m_ints = resizedInts(t);
+			}
+
+			IntArray b = new IntArray(other.resizedInts(other.Length + 1));
+			IntArray c = new IntArray((m + m + 31) >> 5);
+			// IntArray c = new IntArray(t + t);
+			int testBit = 1;
+			for (int k = 0; k < 32; k++)
+			{
+				for (int j = 0; j < t; j++)
+				{
+					if ((m_ints[j] & testBit) != 0)
+					{
+						// The kth bit of m_ints[j] is set
+						c.AddShifted(b, j);
+					}
+				}
+				testBit <<= 1;
+				b.ShiftLeft();
+			}
+			return c;
+		}
+
+		// public IntArray multiplyLeftToRight(IntArray other, int m) {
+		// // Lenght of c is 2m bits rounded up to the next int (32 bit)
+		// int t = (m + 31) / 32;
+		// if (m_ints.Length < t) {
+		// m_ints = resizedInts(t);
+		// }
+		//
+		// IntArray b = new IntArray(other.resizedInts(other.getLength() + 1));
+		// IntArray c = new IntArray((m + m + 31) / 32);
+		// // IntArray c = new IntArray(t + t);
+		// int testBit = 1 << 31;
+		// for (int k = 31; k >= 0; k--) {
+		// for (int j = 0; j < t; j++) {
+		// if ((m_ints[j] & testBit) != 0) {
+		// // The kth bit of m_ints[j] is set
+		// c.addShifted(b, j);
+		// }
+		// }
+		// testBit >>>= 1;
+		// if (k > 0) {
+		// c.shiftLeft();
+		// }
+		// }
+		// return c;
+		// }
+
+		// TODO note, redPol.Length must be 3 for TPB and 5 for PPB
+		public void Reduce(int m, int[] redPol)
+		{
+			for (int i = m + m - 2; i >= m; i--)
+			{
+				if (TestBit(i))
+				{
+					int bit = i - m;
+					FlipBit(bit);
+					FlipBit(i);
+					int l = redPol.Length;
+					while (--l >= 0)
+					{
+						FlipBit(redPol[l] + bit);
+					}
+				}
+			}
+			m_ints = resizedInts((m + 31) >> 5);
+		}
+
+		public IntArray Square(int m)
+		{
+			// TODO make the table static readonly
+			int[] table = { 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15, 0x40,
+									0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55 };
+
+			int t = (m + 31) >> 5;
+			if (m_ints.Length < t)
+			{
+				m_ints = resizedInts(t);
+			}
+
+			IntArray c = new IntArray(t + t);
+
+			// TODO twice the same code, put in separate private method
+			for (int i = 0; i < t; i++)
+			{
+				int v0 = 0;
+				for (int j = 0; j < 4; j++)
+				{
+					v0 = (int)((uint) v0 >> 8);
+					int u = (int)((uint)m_ints[i] >> (j * 4)) & 0xF;
+					int w = table[u] << 24;
+					v0 |= w;
+				}
+				c.m_ints[i + i] = v0;
+
+				v0 = 0;
+				int upper = (int)((uint) m_ints[i] >> 16);
+				for (int j = 0; j < 4; j++)
+				{
+					v0 = (int)((uint) v0 >> 8);
+					int u = (int)((uint)upper >> (j * 4)) & 0xF;
+					int w = table[u] << 24;
+					v0 |= w;
+				}
+				c.m_ints[i + i + 1] = v0;
+			}
+			return c;
+		}
+
+		public override bool Equals(object o)
+		{
+			if (!(o is IntArray))
+			{
+				return false;
+			}
+			IntArray other = (IntArray) o;
+			int usedLen = GetUsedLength();
+			if (other.GetUsedLength() != usedLen)
+			{
+				return false;
+			}
+			for (int i = 0; i < usedLen; i++)
+			{
+				if (m_ints[i] != other.m_ints[i])
+				{
+					return false;
+				}
+			}
+			return true;
+		}
+
+		public override int GetHashCode()
+		{
+			int i = GetUsedLength();
+			int hc = i;
+			while (--i >= 0)
+			{
+				hc *= 17;
+				hc ^= m_ints[i];
+			}
+			return hc;
+		}
+
+		internal IntArray Copy()
+		{
+			return new IntArray((int[]) m_ints.Clone());
+		}
+
+		public override string ToString()
+		{
+			int usedLen = GetUsedLength();
+			if (usedLen == 0)
+			{
+				return "0";
+			}
+
+			StringBuilder sb = new StringBuilder(Convert.ToString(m_ints[usedLen - 1], 2));
+			for (int iarrJ = usedLen - 2; iarrJ >= 0; iarrJ--)
+			{
+				string hexString = Convert.ToString(m_ints[iarrJ], 2);
+
+				// Add leading zeroes, except for highest significant int
+				for (int i = hexString.Length; i < 8; i++)
+				{
+					hexString = "0" + hexString;
+				}
+				sb.Append(hexString);
+			}
+			return sb.ToString();
+		}
+	}
+}
diff --git a/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
new file mode 100644
index 000000000..225fc3075
--- /dev/null
+++ b/Crypto/src/math/ec/abc/Tnaf.cs
@@ -0,0 +1,834 @@
+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;
+		}
+	}
+}
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/multiplier/ECMultiplier.cs b/Crypto/src/math/ec/multiplier/ECMultiplier.cs
new file mode 100644
index 000000000..c6d768ea8
--- /dev/null
+++ b/Crypto/src/math/ec/multiplier/ECMultiplier.cs
@@ -0,0 +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);
+	}
+}
diff --git a/Crypto/src/math/ec/multiplier/FpNafMultiplier.cs b/Crypto/src/math/ec/multiplier/FpNafMultiplier.cs
new file mode 100644
index 000000000..f5a98501a
--- /dev/null
+++ b/Crypto/src/math/ec/multiplier/FpNafMultiplier.cs
@@ -0,0 +1,39 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+	/**
+	* Class implementing the NAF (Non-Adjacent Form) multiplication algorithm.
+	*/
+	internal class FpNafMultiplier
+		: ECMultiplier
+	{
+		/**
+		* D.3.2 pg 101
+		* @see org.bouncycastle.math.ec.multiplier.ECMultiplier#multiply(org.bouncycastle.math.ec.ECPoint, java.math.BigInteger)
+		*/
+		public ECPoint Multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
+		{
+			// TODO Probably should try to add this
+			// BigInteger e = k.Mod(n); // n == order of p
+			BigInteger e = k;
+			BigInteger h = e.Multiply(BigInteger.Three);
+
+			ECPoint neg = p.Negate();
+			ECPoint R = p;
+
+			for (int i = h.BitLength - 2; i > 0; --i)
+			{             
+				R = R.Twice();
+
+				bool hBit = h.TestBit(i);
+				bool eBit = e.TestBit(i);
+
+				if (hBit != eBit)
+				{
+					R = R.Add(hBit ? p : neg);
+				}
+			}
+
+			return R;
+		}
+	}
+}
diff --git a/Crypto/src/math/ec/multiplier/PreCompInfo.cs b/Crypto/src/math/ec/multiplier/PreCompInfo.cs
new file mode 100644
index 000000000..d379508c8
--- /dev/null
+++ b/Crypto/src/math/ec/multiplier/PreCompInfo.cs
@@ -0,0 +1,11 @@
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+	/**
+	* Interface for classes storing precomputation data for multiplication
+	* algorithms. Used as a Memento (see GOF patterns) for
+	* <code>WNafMultiplier</code>.
+	*/
+	internal interface PreCompInfo
+	{
+	}
+}
diff --git a/Crypto/src/math/ec/multiplier/ReferenceMultiplier.cs b/Crypto/src/math/ec/multiplier/ReferenceMultiplier.cs
new file mode 100644
index 000000000..cdccffc2d
--- /dev/null
+++ b/Crypto/src/math/ec/multiplier/ReferenceMultiplier.cs
@@ -0,0 +1,30 @@
+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;
+		}
+	}
+}
diff --git a/Crypto/src/math/ec/multiplier/WNafMultiplier.cs b/Crypto/src/math/ec/multiplier/WNafMultiplier.cs
new file mode 100644
index 000000000..b5cf34ba8
--- /dev/null
+++ b/Crypto/src/math/ec/multiplier/WNafMultiplier.cs
@@ -0,0 +1,241 @@
+using System;
+
+namespace Org.BouncyCastle.Math.EC.Multiplier
+{
+	/**
+	* Class implementing the WNAF (Window Non-Adjacent Form) multiplication
+	* algorithm.
+	*/
+	internal class WNafMultiplier
+		: ECMultiplier 
+	{
+		/**
+		* Computes the Window NAF (non-adjacent Form) of an integer.
+		* @param width The width <code>w</code> of the Window NAF. The width is
+		* defined as the minimal number <code>w</code>, such that for any
+		* <code>w</code> consecutive digits in the resulting representation, at
+		* most one is non-zero.
+		* @param k The integer of which the Window NAF is computed.
+		* @return The Window NAF of the given width, such that the following holds:
+		* <code>k = &#8722;<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>sbyte[]</code>.
+		*/
+		public sbyte[] WindowNaf(sbyte width, BigInteger k)
+		{
+			// The window NAF is at most 1 element longer than the binary
+			// representation of the integer k. sbyte can be used instead of short or
+			// int unless the window width is larger than 8. For larger width use
+			// short or int. However, a width of more than 8 is not efficient for
+			// m = log2(q) smaller than 2305 Bits. Note: Values for m larger than
+			// 1000 Bits are currently not used in practice.
+			sbyte[] wnaf = new sbyte[k.BitLength + 1];
+
+			// 2^width as short and BigInteger
+			short pow2wB = (short)(1 << width);
+			BigInteger pow2wBI = BigInteger.ValueOf(pow2wB);
+
+			int i = 0;
+
+			// The actual length of the WNAF
+			int length = 0;
+
+			// while k >= 1
+			while (k.SignValue > 0)
+			{
+				// if k is odd
+				if (k.TestBit(0))
+				{
+					// k Mod 2^width
+					BigInteger remainder = k.Mod(pow2wBI);
+
+					// if remainder > 2^(width - 1) - 1
+					if (remainder.TestBit(width - 1))
+					{
+						wnaf[i] = (sbyte)(remainder.IntValue - pow2wB);
+					}
+					else
+					{
+						wnaf[i] = (sbyte)remainder.IntValue;
+					}
+					// wnaf[i] is now in [-2^(width-1), 2^(width-1)-1]
+
+					k = k.Subtract(BigInteger.ValueOf(wnaf[i]));
+					length = i;
+				}
+				else
+				{
+					wnaf[i] = 0;
+				}
+
+				// k = k/2
+				k = k.ShiftRight(1);
+				i++;
+			}
+
+			length++;
+
+			// Reduce the WNAF array to its actual length
+			sbyte[] wnafShort = new sbyte[length];
+			Array.Copy(wnaf, 0, wnafShort, 0, length);
+			return wnafShort;
+		}
+
+		/**
+		* Multiplies <code>this</code> by an integer <code>k</code> using the
+		* Window NAF method.
+		* @param k The integer by which <code>this</code> is multiplied.
+		* @return A new <code>ECPoint</code> which equals <code>this</code>
+		* multiplied by <code>k</code>.
+		*/
+		public ECPoint Multiply(ECPoint p, BigInteger k, PreCompInfo preCompInfo)
+		{
+			WNafPreCompInfo wnafPreCompInfo;
+
+			if ((preCompInfo != null) && (preCompInfo is WNafPreCompInfo))
+			{
+				wnafPreCompInfo = (WNafPreCompInfo)preCompInfo;
+			}
+			else
+			{
+				// Ignore empty PreCompInfo or PreCompInfo of incorrect type
+				wnafPreCompInfo = new WNafPreCompInfo();
+			}
+
+			// floor(log2(k))
+			int m = k.BitLength;
+
+			// width of the Window NAF
+			sbyte width;
+
+			// Required length of precomputation array
+			int reqPreCompLen;
+
+			// Determine optimal width and corresponding length of precomputation
+			// array based on literature values
+			if (m < 13)
+			{
+				width = 2;
+				reqPreCompLen = 1;
+			}
+			else
+			{
+				if (m < 41)
+				{
+					width = 3;
+					reqPreCompLen = 2;
+				}
+				else
+				{
+					if (m < 121)
+					{
+						width = 4;
+						reqPreCompLen = 4;
+					}
+					else
+					{
+						if (m < 337)
+						{
+							width = 5;
+							reqPreCompLen = 8;
+						}
+						else
+						{
+							if (m < 897)
+							{
+								width = 6;
+								reqPreCompLen = 16;
+							}
+							else
+							{
+								if (m < 2305)
+								{
+									width = 7;
+									reqPreCompLen = 32;
+								}
+								else 
+								{
+									width = 8;
+									reqPreCompLen = 127;
+								}
+							}
+						}
+					}
+				}
+			}
+
+			// The length of the precomputation array
+			int preCompLen = 1;
+
+			ECPoint[] preComp = wnafPreCompInfo.GetPreComp();
+			ECPoint twiceP = wnafPreCompInfo.GetTwiceP();
+
+			// Check if the precomputed ECPoints already exist
+			if (preComp == null)
+			{
+				// Precomputation must be performed from scratch, create an empty
+				// precomputation array of desired length
+				preComp = new ECPoint[]{ p };
+			}
+			else
+			{
+				// Take the already precomputed ECPoints to start with
+				preCompLen = preComp.Length;
+			}
+
+			if (twiceP == null)
+			{
+				// Compute twice(p)
+				twiceP = p.Twice();
+			}
+
+			if (preCompLen < reqPreCompLen)
+			{
+				// Precomputation array must be made bigger, copy existing preComp
+				// array into the larger new preComp array
+				ECPoint[] oldPreComp = preComp;
+				preComp = new ECPoint[reqPreCompLen];
+				Array.Copy(oldPreComp, 0, preComp, 0, preCompLen);
+
+				for (int i = preCompLen; i < reqPreCompLen; i++)
+				{
+					// Compute the new ECPoints for the precomputation array.
+					// The values 1, 3, 5, ..., 2^(width-1)-1 times p are
+					// computed
+					preComp[i] = twiceP.Add(preComp[i - 1]);
+				}            
+			}
+
+			// Compute the Window NAF of the desired width
+			sbyte[] wnaf = WindowNaf(width, k);
+			int l = wnaf.Length;
+
+			// Apply the Window NAF to p using the precomputed ECPoint values.
+			ECPoint q = p.Curve.Infinity;
+			for (int i = l - 1; i >= 0; i--)
+			{
+				q = q.Twice();
+
+				if (wnaf[i] != 0)
+				{
+					if (wnaf[i] > 0)
+					{
+						q = q.Add(preComp[(wnaf[i] - 1)/2]);
+					}
+					else
+					{
+						// wnaf[i] < 0
+						q = q.Subtract(preComp[(-wnaf[i] - 1)/2]);
+					}
+				}
+			}
+
+			// Set PreCompInfo in ECPoint, such that it is available for next
+			// multiplication.
+			wnafPreCompInfo.SetPreComp(preComp);
+			wnafPreCompInfo.SetTwiceP(twiceP);
+			p.SetPreCompInfo(wnafPreCompInfo);
+			return q;
+		}
+	}
+}
diff --git a/Crypto/src/math/ec/multiplier/WNafPreCompInfo.cs b/Crypto/src/math/ec/multiplier/WNafPreCompInfo.cs
new file mode 100644
index 000000000..d9305dace
--- /dev/null
+++ b/Crypto/src/math/ec/multiplier/WNafPreCompInfo.cs
@@ -0,0 +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;
+
+		/**
+		* 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;
+
+		internal ECPoint[] GetPreComp()
+		{
+			return preComp;
+		}
+
+		internal void SetPreComp(ECPoint[] preComp)
+		{
+			this.preComp = preComp;
+		}
+
+		internal ECPoint GetTwiceP()
+		{
+			return twiceP;
+		}
+
+		internal void SetTwiceP(ECPoint twiceThis)
+		{
+			this.twiceP = twiceThis;
+		}
+	}
+}
diff --git a/Crypto/src/math/ec/multiplier/WTauNafMultiplier.cs b/Crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
new file mode 100644
index 000000000..f1a605770
--- /dev/null
+++ b/Crypto/src/math/ec/multiplier/WTauNafMultiplier.cs
@@ -0,0 +1,120 @@
+using System;
+
+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");
+
+			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);
+
+			return MultiplyWTnaf(p, rho, preCompInfo, 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;
+			}
+
+			BigInteger tw = Tnaf.GetTw(mu, Tnaf.Width);
+
+			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;
+
+			F2mPoint[] pu;
+			if ((preCompInfo == null) || !(preCompInfo is WTauNafPreCompInfo))
+			{
+				pu = Tnaf.GetPreComp(p, a);
+				p.SetPreCompInfo(new WTauNafPreCompInfo(pu));
+			}
+			else
+			{
+				pu = ((WTauNafPreCompInfo)preCompInfo).GetPreComp();
+			}
+
+			// 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]]);
+					}
+				}
+			}
+
+			return q;
+		}
+	}
+}
diff --git a/Crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs b/Crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
new file mode 100644
index 000000000..cede4a05d
--- /dev/null
+++ b/Crypto/src/math/ec/multiplier/WTauNafPreCompInfo.cs
@@ -0,0 +1,41 @@
+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;
+
+		/**
+		* 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;
+		}
+	}
+}
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
new file mode 100644
index 000000000..44eed9f32
--- /dev/null
+++ b/Crypto/src/ocsp/OCSPException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	public class OcspException
+		: Exception
+	{
+		public OcspException()
+		{
+		}
+
+		public OcspException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public OcspException(
+			string		message,
+			Exception	e)
+			: base(message, e)
+		{
+		}
+	}
+}
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
new file mode 100644
index 000000000..dad56dc39
--- /dev/null
+++ b/Crypto/src/ocsp/OCSPUtil.cs
@@ -0,0 +1,133 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Ocsp
+{
+	class OcspUtilities
+	{
+		private static readonly IDictionary algorithms = Platform.CreateHashtable();
+        private static readonly IDictionary oids = Platform.CreateHashtable();
+		private static readonly ISet noParams = new HashSet();
+
+		static OcspUtilities()
+		{
+			algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+			algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+			algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+			algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+			algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+			algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+			algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+			algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+			algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+			algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+			algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+			algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+			algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+			algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+			algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+			algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+			algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+			algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+			algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+			algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+			algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1);
+			algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1);
+			algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+			algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+			algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+			algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+			algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+			algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+			algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+			algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+			algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+			algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+
+			oids.Add(PkcsObjectIdentifiers.MD2WithRsaEncryption, "MD2WITHRSA");
+			oids.Add(PkcsObjectIdentifiers.MD5WithRsaEncryption, "MD5WITHRSA");
+			oids.Add(PkcsObjectIdentifiers.Sha1WithRsaEncryption, "SHA1WITHRSA");
+			oids.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption, "SHA224WITHRSA");
+			oids.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption, "SHA256WITHRSA");
+			oids.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption, "SHA384WITHRSA");
+			oids.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption, "SHA512WITHRSA");
+			oids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160, "RIPEMD160WITHRSA");
+			oids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128, "RIPEMD128WITHRSA");
+			oids.Add(TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256, "RIPEMD256WITHRSA");
+			oids.Add(X9ObjectIdentifiers.IdDsaWithSha1, "SHA1WITHDSA");
+			oids.Add(NistObjectIdentifiers.DsaWithSha224, "SHA224WITHDSA");
+			oids.Add(NistObjectIdentifiers.DsaWithSha256, "SHA256WITHDSA");
+			oids.Add(X9ObjectIdentifiers.ECDsaWithSha1, "SHA1WITHECDSA");
+			oids.Add(X9ObjectIdentifiers.ECDsaWithSha224, "SHA224WITHECDSA");
+			oids.Add(X9ObjectIdentifiers.ECDsaWithSha256, "SHA256WITHECDSA");
+			oids.Add(X9ObjectIdentifiers.ECDsaWithSha384, "SHA384WITHECDSA");
+			oids.Add(X9ObjectIdentifiers.ECDsaWithSha512, "SHA512WITHECDSA");
+			oids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, "GOST3411WITHGOST3410");
+
+			//
+			// According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+			// The parameters field SHALL be NULL for RSA based signature algorithms.
+			//
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+			noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+			noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+			noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+		}
+
+		internal static DerObjectIdentifier GetAlgorithmOid(
+			string algorithmName)
+		{
+			algorithmName = algorithmName.ToUpperInvariant();
+
+			if (algorithms.Contains(algorithmName))
+			{
+				return (DerObjectIdentifier)algorithms[algorithmName];
+			}
+
+			return new DerObjectIdentifier(algorithmName);
+		}
+
+
+		internal static string GetAlgorithmName(
+			DerObjectIdentifier oid)
+		{
+			if (oids.Contains(oid))
+			{
+				return (string)oids[oid];
+			}
+
+			return oid.Id;
+		}
+
+		internal static AlgorithmIdentifier GetSigAlgID(
+			DerObjectIdentifier sigOid)
+		{
+			if (noParams.Contains(sigOid))
+			{
+				return new AlgorithmIdentifier(sigOid);
+			}
+
+			return new AlgorithmIdentifier(sigOid, DerNull.Instance);
+		}
+
+		internal static IEnumerable AlgNames
+		{
+			get { return new EnumerableProxy(algorithms.Keys); }
+		}
+	}
+}
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
new file mode 100644
index 000000000..c758ecb05
--- /dev/null
+++ b/Crypto/src/openpgp/PgpCompressedDataGenerator.cs
@@ -0,0 +1,203 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Apache.Bzip2;
+using Org.BouncyCastle.Utilities.Zlib;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Class for producing compressed data packets.</remarks>
+	public class PgpCompressedDataGenerator
+		: IStreamGenerator
+	{
+		private readonly CompressionAlgorithmTag algorithm;
+		private readonly int compression;
+
+		private Stream dOut;
+		private BcpgOutputStream pkOut;
+
+		public PgpCompressedDataGenerator(
+			CompressionAlgorithmTag algorithm)
+			: this(algorithm, JZlib.Z_DEFAULT_COMPRESSION)
+		{
+		}
+
+		public PgpCompressedDataGenerator(
+			CompressionAlgorithmTag	algorithm,
+			int						compression)
+		{
+			switch (algorithm)
+			{
+				case CompressionAlgorithmTag.Uncompressed:
+				case CompressionAlgorithmTag.Zip:
+				case CompressionAlgorithmTag.ZLib:
+				case CompressionAlgorithmTag.BZip2:
+					break;
+				default:
+					throw new ArgumentException("unknown compression algorithm", "algorithm");
+			}
+
+			if (compression != JZlib.Z_DEFAULT_COMPRESSION)
+			{
+				if ((compression < JZlib.Z_NO_COMPRESSION) || (compression > JZlib.Z_BEST_COMPRESSION))
+				{
+					throw new ArgumentException("unknown compression level: " + compression);
+				}
+			}
+
+			this.algorithm = algorithm;
+			this.compression = compression;
+		}
+
+		/// <summary>
+		/// <p>
+		/// Return an output stream which will save the data being written to
+		/// the compressed object.
+		/// </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>
+		/// <param name="outStr">Stream to be used for output.</param>
+		/// <returns>A Stream for output of the compressed data.</returns>
+		/// <exception cref="ArgumentNullException"></exception>
+		/// <exception cref="InvalidOperationException"></exception>
+		/// <exception cref="IOException"></exception>
+		public Stream Open(
+			Stream outStr)
+		{
+			if (dOut != null)
+				throw new InvalidOperationException("generator already in open state");
+			if (outStr == null)
+				throw new ArgumentNullException("outStr");
+
+			this.pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData);
+
+			doOpen();
+
+			return new WrappedGeneratorStream(this, dOut);
+		}
+
+		/// <summary>
+		/// <p>
+		/// Return an output stream which will compress 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>
+		/// <p>
+		/// <b>Note</b>: using this may break compatibility with RFC 1991 compliant tools.
+		/// Only recent OpenPGP implementations are capable of accepting these streams.
+		/// </p>
+		/// </summary>
+		/// <param name="outStr">Stream to be used for output.</param>
+		/// <param name="buffer">The buffer to use.</param>
+		/// <returns>A Stream for output of the compressed data.</returns>
+		/// <exception cref="ArgumentNullException"></exception>
+		/// <exception cref="InvalidOperationException"></exception>
+		/// <exception cref="IOException"></exception>
+		/// <exception cref="PgpException"></exception>
+		public Stream Open(
+			Stream	outStr,
+			byte[]	buffer)
+		{
+			if (dOut != null)
+				throw new InvalidOperationException("generator already in open state");
+			if (outStr == null)
+				throw new ArgumentNullException("outStr");
+			if (buffer == null)
+				throw new ArgumentNullException("buffer");
+
+			this.pkOut = new BcpgOutputStream(outStr, PacketTag.CompressedData, buffer);
+
+			doOpen();
+
+			return new WrappedGeneratorStream(this, dOut);
+		}
+
+		private void doOpen()
+		{
+			pkOut.WriteByte((byte) algorithm);
+
+			switch (algorithm)
+			{
+				case CompressionAlgorithmTag.Uncompressed:
+					dOut = pkOut;
+					break;
+				case CompressionAlgorithmTag.Zip:
+					dOut = new SafeZOutputStream(pkOut, compression, true);
+					break;
+				case CompressionAlgorithmTag.ZLib:
+					dOut = new SafeZOutputStream(pkOut, compression, false);
+					break;
+				case CompressionAlgorithmTag.BZip2:
+					dOut = new SafeCBZip2OutputStream(pkOut);
+					break;
+				default:
+					// Constructor should guard against this possibility
+					throw new InvalidOperationException();
+			}
+		}
+
+		/// <summary>Close the compressed object.</summary>summary>
+		public void Close()
+		{
+			if (dOut != null)
+			{
+				if (dOut != pkOut)
+				{
+                    dOut.Dispose();
+					dOut.Flush();
+				}
+
+				dOut = null;
+
+				pkOut.Finish();
+				pkOut.Flush();
+				pkOut = null;
+			}
+		}
+
+		private class SafeCBZip2OutputStream : CBZip2OutputStream
+		{
+			public SafeCBZip2OutputStream(Stream output)
+				: base(output)
+			{
+			}
+
+            protected override void Dispose(bool disposing)
+            {
+                if (disposing)
+                {
+                    Finish();
+                }
+            }
+		}
+
+		private class SafeZOutputStream : ZOutputStream
+		{
+			public SafeZOutputStream(Stream output, int level, bool nowrap)
+				: base(output, level, nowrap)
+			{
+			}
+
+            protected override void Dispose(bool disposing)
+            {
+                if (disposing)
+                {
+                    Finish();
+                    End();
+                }
+            }
+		}
+	}
+}
diff --git a/Crypto/src/openpgp/PgpDataValidationException.cs b/Crypto/src/openpgp/PgpDataValidationException.cs
new file mode 100644
index 000000000..74674da59
--- /dev/null
+++ b/Crypto/src/openpgp/PgpDataValidationException.cs
@@ -0,0 +1,15 @@
+using System;
+
+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>
+    public class PgpDataValidationException
+        : PgpException
+	{
+		public PgpDataValidationException() : base() {}
+		public PgpDataValidationException(string message) : base(message) {}
+		public PgpDataValidationException(string message, Exception exception) : base(message, exception) {}
+	}
+}
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
new file mode 100644
index 000000000..3048116fa
--- /dev/null
+++ b/Crypto/src/openpgp/PgpException.cs
@@ -0,0 +1,19 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Generic exception class for PGP encoding/decoding problems.</remarks>
+	public class PgpException
+		: Exception
+	{
+		public PgpException() : base() {}
+		public PgpException(string message) : base(message) {}
+		public PgpException(string message, Exception exception) : base(message, exception) {}
+
+		[Obsolete("Use InnerException property")]
+		public Exception UnderlyingException
+		{
+			get { return InnerException; }
+		}
+	}
+}
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
new file mode 100644
index 000000000..da07f400f
--- /dev/null
+++ b/Crypto/src/openpgp/PgpKeyValidationException.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>
+	/// Thrown if the key checksum is invalid.
+	/// </remarks>
+	public class PgpKeyValidationException
+		: PgpException
+	{
+		public PgpKeyValidationException() : base() {}
+		public PgpKeyValidationException(string message) : base(message) {}
+		public PgpKeyValidationException(string message, Exception exception) : base(message, exception) {}
+	}
+}
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
new file mode 100644
index 000000000..b0337c80d
--- /dev/null
+++ b/Crypto/src/openpgp/PgpLiteralDataGenerator.cs
@@ -0,0 +1,180 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Class for producing literal data packets.</remarks>
+    public class PgpLiteralDataGenerator
+		: IStreamGenerator
+	{
+        public const char Binary = PgpLiteralData.Binary;
+        public const char Text = PgpLiteralData.Text;
+		public const char Utf8 = PgpLiteralData.Utf8;
+
+		/// <summary>The special name indicating a "for your eyes only" packet.</summary>
+        public const string Console = PgpLiteralData.Console;
+
+		private BcpgOutputStream pkOut;
+        private bool oldFormat;
+
+		public PgpLiteralDataGenerator()
+        {
+        }
+
+		/// <summary>
+		/// Generates literal data objects in the old format.
+		/// This is important if you need compatibility with PGP 2.6.x.
+		/// </summary>
+		/// <param name="oldFormat">If true, uses old format.</param>
+        public PgpLiteralDataGenerator(
+            bool oldFormat)
+        {
+            this.oldFormat = oldFormat;
+        }
+
+		private void WriteHeader(
+            BcpgOutputStream	outStr,
+            char				format,
+            string				name,
+            long				modificationTime)
+        {
+			byte[] encName = Strings.ToUtf8ByteArray(name);
+
+			outStr.Write(
+				(byte) format,
+				(byte) encName.Length);
+
+			outStr.Write(encName);
+
+			long modDate = modificationTime / 1000L;
+
+			outStr.Write(
+				(byte)(modDate >> 24),
+				(byte)(modDate >> 16),
+				(byte)(modDate >> 8),
+				(byte)modDate);
+        }
+
+		/// <summary>
+		/// <p>
+		/// Open a literal data packet, returning a stream to store the data inside the 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>
+		/// <param name="outStr">The stream we want the packet in.</param>
+		/// <param name="format">The format we are using.</param>
+		/// <param name="name">The name of the 'file'.</param>
+		/// <param name="length">The length of the data we will write.</param>
+		/// <param name="modificationTime">The time of last modification we want stored.</param>
+        public Stream Open(
+            Stream		outStr,
+            char		format,
+            string		name,
+            long		length,
+            DateTime	modificationTime)
+        {
+			if (pkOut != null)
+				throw new InvalidOperationException("generator already in open state");
+			if (outStr == null)
+				throw new ArgumentNullException("outStr");
+
+			// 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);
+
+			WriteHeader(pkOut, format, name, unixMs);
+
+			return new WrappedGeneratorStream(this, pkOut);
+        }
+
+		/// <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
+		/// packets with a chunk size determined by 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>
+		/// <param name="outStr">The stream we want the packet in.</param>
+		/// <param name="format">The format we are using.</param>
+		/// <param name="name">The name of the 'file'.</param>
+		/// <param name="modificationTime">The time of last modification we want stored.</param>
+		/// <param name="buffer">The buffer to use for collecting data to put into chunks.</param>
+        public Stream Open(
+            Stream		outStr,
+            char		format,
+            string		name,
+            DateTime	modificationTime,
+            byte[]		buffer)
+        {
+			if (pkOut != null)
+				throw new InvalidOperationException("generator already in open state");
+			if (outStr == null)
+				throw new ArgumentNullException("outStr");
+
+			// Do this first, since it might throw an exception
+			long unixMs = DateTimeUtilities.DateTimeToUnixMs(modificationTime);
+
+			pkOut = new BcpgOutputStream(outStr, PacketTag.LiteralData, buffer);
+
+			WriteHeader(pkOut, format, name, unixMs);
+
+			return new WrappedGeneratorStream(this, pkOut);
+		}
+
+#if !PORTABLE
+		/// <summary>
+		/// <p>
+		/// Open a literal data packet for the passed in <c>FileInfo</c> object, returning
+		/// an output stream for saving the file contents.
+		/// </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>
+		/// <param name="outStr">The stream we want the packet in.</param>
+		/// <param name="format">The format we are using.</param>
+		/// <param name="file">The <c>FileInfo</c> object containg the packet details.</param>
+		public Stream Open(
+            Stream		outStr,
+            char		format,
+            FileInfo	file)
+        {
+			return Open(outStr, format, file.Name, file.Length, file.LastWriteTime);
+        }
+#endif
+
+		/// <summary>
+		/// Close the literal data packet - this is equivalent to calling Close()
+		/// on the stream returned by the Open() method.
+		/// </summary>
+        public void Close()
+        {
+			if (pkOut != null)
+			{
+				pkOut.Finish();
+				pkOut.Flush();
+				pkOut = null;
+			}
+		}
+	}
+}
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
new file mode 100644
index 000000000..ecb935e4b
--- /dev/null
+++ b/Crypto/src/openpgp/PgpPublicKeyRing.cs
@@ -0,0 +1,200 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+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
+    {
+        private readonly IList keys;
+
+		public PgpPublicKeyRing(
+            byte[] encoding)
+            : this(new MemoryStream(encoding, false))
+        {
+        }
+
+		internal PgpPublicKeyRing(
+            IList pubKeys)
+        {
+            this.keys = pubKeys;
+        }
+
+		public PgpPublicKeyRing(
+            Stream inputStream)
+        {
+			this.keys = Platform.CreateArrayList();
+
+            BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
+
+			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"));
+            }
+
+			PublicKeyPacket pubPk = (PublicKeyPacket) bcpgInput.ReadPacket();;
+			TrustPacket trustPk = ReadOptionalTrustPacket(bcpgInput);
+
+            // direct signatures and revocations
+			IList keySigs = ReadSignaturesAndTrust(bcpgInput);
+
+			IList ids, idTrusts, idSigs;
+			ReadUserIDs(bcpgInput, out ids, out idTrusts, out idSigs);
+
+			keys.Add(new PgpPublicKey(pubPk, trustPk, keySigs, ids, idTrusts, idSigs));
+
+
+			// Read subkeys
+			while (bcpgInput.NextPacketTag() == PacketTag.PublicSubkey)
+            {
+				keys.Add(ReadSubkey(bcpgInput));
+            }
+        }
+
+		/// <summary>Return the first public key in the ring.</summary>
+        public 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(
+            long keyId)
+        {
+			foreach (PgpPublicKey k in keys)
+			{
+				if (keyId == k.KeyId)
+                {
+                    return k;
+                }
+            }
+
+			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()
+        {
+            return new EnumerableProxy(keys);
+        }
+
+		public byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+
+			Encode(bOut);
+
+			return bOut.ToArray();
+        }
+
+		public void Encode(
+            Stream outStr)
+        {
+			if (outStr == null)
+				throw new ArgumentNullException("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>
+        public static PgpPublicKeyRing InsertPublicKey(
+            PgpPublicKeyRing	pubRing,
+            PgpPublicKey		pubKey)
+        {
+            IList keys = Platform.CreateArrayList(pubRing.keys);
+            bool found = false;
+			bool masterFound = false;
+
+			for (int i = 0; i != keys.Count; i++)
+            {
+                PgpPublicKey key = (PgpPublicKey) keys[i];
+
+				if (key.KeyId == pubKey.KeyId)
+                {
+                    found = true;
+                    keys[i] = pubKey;
+                }
+				if (key.IsMasterKey)
+				{
+					masterFound = true;
+				}
+			}
+
+			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);
+        }
+
+		/// <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)
+        {
+            IList keys = Platform.CreateArrayList(pubRing.keys);
+            bool found = false;
+
+			for (int i = 0; i < keys.Count; i++)
+            {
+                PgpPublicKey key = (PgpPublicKey) keys[i];
+
+				if (key.KeyId == pubKey.KeyId)
+                {
+                    found = true;
+                    keys.RemoveAt(i);
+                }
+            }
+
+			return found ? new PgpPublicKeyRing(keys) : null;
+        }
+
+		internal static PgpPublicKey ReadSubkey(BcpgInputStream bcpgInput)
+		{
+            PublicKeyPacket	pk = (PublicKeyPacket) bcpgInput.ReadPacket();
+			TrustPacket kTrust = ReadOptionalTrustPacket(bcpgInput);
+
+			// PGP 8 actually leaves out the signature.
+			IList sigList = ReadSignaturesAndTrust(bcpgInput);
+
+			return new PgpPublicKey(pk, kTrust, sigList);
+		}
+    }
+}
diff --git a/Crypto/src/openpgp/PgpPublicKeyRingBundle.cs b/Crypto/src/openpgp/PgpPublicKeyRingBundle.cs
new file mode 100644
index 000000000..77cede4a1
--- /dev/null
+++ b/Crypto/src/openpgp/PgpPublicKeyRingBundle.cs
@@ -0,0 +1,280 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>
+	/// Often a PGP key ring file is made up of a succession of master/sub-key key rings.
+	/// If you want to read an entire public key file in one hit this is the class for you.
+	/// </remarks>
+    public class PgpPublicKeyRingBundle
+    {
+        private readonly IDictionary pubRings;
+        private readonly IList order;
+
+		private PgpPublicKeyRingBundle(
+            IDictionary	pubRings,
+            IList       order)
+        {
+            this.pubRings = pubRings;
+            this.order = order;
+        }
+
+		public PgpPublicKeyRingBundle(
+            byte[] encoding)
+            : this(new MemoryStream(encoding, false))
+        {
+        }
+
+		/// <summary>Build a PgpPublicKeyRingBundle from the passed in input stream.</summary>
+		/// <param name="inputStream">Input stream containing data.</param>
+		/// <exception cref="IOException">If a problem parsing the stream occurs.</exception>
+		/// <exception cref="PgpException">If an object is encountered which isn't a PgpPublicKeyRing.</exception>
+		public PgpPublicKeyRingBundle(
+            Stream inputStream)
+			: this(new PgpObjectFactory(inputStream).AllPgpObjects())
+		{
+        }
+
+		public PgpPublicKeyRingBundle(
+            IEnumerable e)
+        {
+			this.pubRings = Platform.CreateHashtable();
+			this.order = Platform.CreateArrayList();
+
+			foreach (object obj in e)
+            {
+				PgpPublicKeyRing pgpPub = obj as PgpPublicKeyRing;
+
+				if (pgpPub == null)
+				{
+					throw new PgpException(obj.GetType().FullName + " found where PgpPublicKeyRing expected");
+				}
+
+				long key = pgpPub.GetPublicKey().KeyId;
+                pubRings.Add(key, pgpPub);
+				order.Add(key);
+            }
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+		{
+			get { return order.Count; }
+		}
+
+		/// <summary>Return the number of key rings in this collection.</summary>
+        public int Count
+        {
+			get { return order.Count; }
+        }
+
+		/// <summary>Allow enumeration of the public key rings making up this collection.</summary>
+        public IEnumerable GetKeyRings()
+        {
+			return new EnumerableProxy(pubRings.Values);
+        }
+
+		/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+		/// <param name="userId">The user ID to be matched.</param>
+		/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+		public IEnumerable GetKeyRings(
+			string userId)
+		{
+			return GetKeyRings(userId, false, false);
+		}
+
+		/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+		/// <param name="userId">The user ID to be matched.</param>
+		/// <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+		/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+        public IEnumerable GetKeyRings(
+            string	userId,
+            bool	matchPartial)
+        {
+			return GetKeyRings(userId, matchPartial, false);
+        }
+
+		/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+		/// <param name="userId">The user ID to be matched.</param>
+		/// <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+		/// <param name="ignoreCase">If true, case is ignored in user ID comparisons.</param>
+		/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+		public IEnumerable GetKeyRings(
+			string	userId,
+			bool	matchPartial,
+			bool	ignoreCase)
+		{
+			IList rings = Platform.CreateArrayList();
+
+			if (ignoreCase)
+			{
+				userId = userId.ToLowerInvariant();
+			}
+
+			foreach (PgpPublicKeyRing pubRing in GetKeyRings())
+			{
+				foreach (string nextUserID in pubRing.GetPublicKey().GetUserIds())
+				{
+					string next = nextUserID;
+					if (ignoreCase)
+					{
+						next = next.ToLowerInvariant();
+					}
+
+					if (matchPartial)
+					{
+						if (next.IndexOf(userId) > -1)
+						{
+							rings.Add(pubRing);
+						}
+					}
+					else
+					{
+						if (next.Equals(userId))
+						{
+							rings.Add(pubRing);
+						}
+					}
+				}
+			}
+
+			return new EnumerableProxy(rings);
+		}
+
+		/// <summary>Return the PGP public key associated with the given key id.</summary>
+		/// <param name="keyId">The ID of the public key to return.</param>
+        public PgpPublicKey GetPublicKey(
+            long keyId)
+        {
+            foreach (PgpPublicKeyRing pubRing in GetKeyRings())
+            {
+                PgpPublicKey pub = pubRing.GetPublicKey(keyId);
+
+				if (pub != null)
+                {
+                    return pub;
+                }
+            }
+
+			return null;
+        }
+
+		/// <summary>Return the public key ring which contains the key referred to by keyId</summary>
+		/// <param name="keyId">key ID to match against</param>
+        public PgpPublicKeyRing GetPublicKeyRing(
+            long keyId)
+        {
+            if (pubRings.Contains(keyId))
+            {
+                return (PgpPublicKeyRing)pubRings[keyId];
+            }
+
+			foreach (PgpPublicKeyRing pubRing in GetKeyRings())
+            {
+                PgpPublicKey pub = pubRing.GetPublicKey(keyId);
+
+                if (pub != null)
+                {
+                    return pubRing;
+                }
+            }
+
+			return null;
+        }
+
+		/// <summary>
+		/// Return true if a key matching the passed in key ID is present, false otherwise.
+		/// </summary>
+		/// <param name="keyID">key ID to look for.</param>
+		public bool Contains(
+			long keyID)
+		{
+			return GetPublicKey(keyID) != null;
+		}
+
+		public byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+
+			Encode(bOut);
+
+			return bOut.ToArray();
+        }
+
+		public void Encode(
+            Stream outStr)
+        {
+			BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+			foreach (long key in order)
+            {
+                PgpPublicKeyRing sec = (PgpPublicKeyRing) pubRings[key];
+
+				sec.Encode(bcpgOut);
+            }
+        }
+
+		/// <summary>
+		/// Return a new bundle containing the contents of the passed in bundle and
+		/// the passed in public key ring.
+		/// </summary>
+		/// <param name="bundle">The <c>PgpPublicKeyRingBundle</c> the key ring is to be added to.</param>
+		/// <param name="publicKeyRing">The key ring to be added.</param>
+		/// <returns>A new <c>PgpPublicKeyRingBundle</c> merging the current one with the passed in key ring.</returns>
+		/// <exception cref="ArgumentException">If the keyId for the passed in key ring is already present.</exception>
+        public static PgpPublicKeyRingBundle AddPublicKeyRing(
+            PgpPublicKeyRingBundle  bundle,
+            PgpPublicKeyRing        publicKeyRing)
+        {
+            long key = publicKeyRing.GetPublicKey().KeyId;
+
+			if (bundle.pubRings.Contains(key))
+            {
+                throw new ArgumentException("Bundle already contains a key with a keyId for the passed in ring.");
+            }
+
+			IDictionary newPubRings = Platform.CreateHashtable(bundle.pubRings);
+            IList newOrder = Platform.CreateArrayList(bundle.order);
+
+			newPubRings[key] = publicKeyRing;
+
+			newOrder.Add(key);
+
+			return new PgpPublicKeyRingBundle(newPubRings, newOrder);
+        }
+
+		/// <summary>
+		/// Return a new bundle containing the contents of the passed in bundle with
+		/// the passed in public key ring removed.
+		/// </summary>
+		/// <param name="bundle">The <c>PgpPublicKeyRingBundle</c> the key ring is to be removed from.</param>
+		/// <param name="publicKeyRing">The key ring to be removed.</param>
+		/// <returns>A new <c>PgpPublicKeyRingBundle</c> not containing the passed in key ring.</returns>
+		/// <exception cref="ArgumentException">If the keyId for the passed in key ring is not present.</exception>
+        public static PgpPublicKeyRingBundle RemovePublicKeyRing(
+            PgpPublicKeyRingBundle	bundle,
+            PgpPublicKeyRing		publicKeyRing)
+        {
+            long key = publicKeyRing.GetPublicKey().KeyId;
+
+			if (!bundle.pubRings.Contains(key))
+            {
+                throw new ArgumentException("Bundle does not contain a key with a keyId for the passed in ring.");
+            }
+
+			IDictionary newPubRings = Platform.CreateHashtable(bundle.pubRings);
+            IList newOrder = Platform.CreateArrayList(bundle.order);
+
+			newPubRings.Remove(key);
+			newOrder.Remove(key);
+
+			return new PgpPublicKeyRingBundle(newPubRings, newOrder);
+        }
+    }
+}
diff --git a/Crypto/src/openpgp/PgpSecretKey.cs b/Crypto/src/openpgp/PgpSecretKey.cs
new file mode 100644
index 000000000..9d87f49c8
--- /dev/null
+++ b/Crypto/src/openpgp/PgpSecretKey.cs
@@ -0,0 +1,666 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <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,
+            char[]						passPhrase,
+			bool						useSha1,
+			SecureRandom				rand,
+			bool						isMasterKey)
+        {
+			BcpgObject secKey;
+
+			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");
+            }
+
+			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.Write(checksumBytes);
+
+				byte[] bOutData = bOut.ToArray();
+
+				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
+                {
+					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);
+					}
+				}
+            }
+            catch (PgpException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("Exception encrypting key", e);
+            }
+        }
+
+		public PgpSecretKey(
+            int							certificationLevel,
+            PgpKeyPair					keyPair,
+            string						id,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            char[]						passPhrase,
+            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
+            {
+				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);
+			}
+        }
+
+		public PgpSecretKey(
+            int							certificationLevel,
+            PublicKeyAlgorithmTag		algorithm,
+            AsymmetricKeyParameter		pubKey,
+            AsymmetricKeyParameter		privKey,
+            DateTime					time,
+            string						id,
+            SymmetricKeyAlgorithmTag	encAlgorithm,
+            char[]						passPhrase,
+            PgpSignatureSubpacketVector	hashedPackets,
+            PgpSignatureSubpacketVector	unhashedPackets,
+            SecureRandom				rand)
+            : this(certificationLevel,
+                new PgpKeyPair(algorithm, pubKey, privKey, time),
+                id, encAlgorithm, passPhrase, hashedPackets, unhashedPackets, rand)
+        {
+        }
+
+		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
+        {
+			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; }
+        }
+
+		/// <summary>The algorithm the key is encrypted with.</summary>
+        public SymmetricKeyAlgorithmTag KeyEncryptionAlgorithm
+        {
+			get { return secret.EncAlgorithm; }
+        }
+
+		/// <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>
+        public PgpPublicKey PublicKey
+        {
+			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>
+        public IEnumerable UserIds
+        {
+			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>
+        public IEnumerable UserAttributes
+        {
+			get { return pub.GetUserAttributes(); }
+        }
+
+		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
+            {
+				KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(secret.EncAlgorithm, secret.S2k, passPhrase);
+				byte[] iv = secret.GetIV();
+
+				if (secret.PublicKeyPacket.Version == 4)
+                {
+					c.Init(false, new ParametersWithIV(key, iv));
+
+					data = c.DoFinal(encData);
+
+					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);
+						}
+					}
+				}
+                else // version 2 or 3, RSA only.
+                {
+					data = new byte[encData.Length];
+
+					//
+                    // read in the four numbers
+                    //
+                    int pos = 0;
+
+					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;
+
+						data[pos] = encData[pos];
+						data[pos + 1] = encData[pos + 1];
+						pos += 2;
+
+						c.DoFinal(encData, pos, encLen, data, pos);
+						pos += encLen;
+
+						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);
+                    int calcCs = 0;
+                    for (int j=0; j < data.Length-2; j++)
+                    {
+                        calcCs += data[j] & 0xff;
+                    }
+
+					calcCs &= 0xffff;
+                    if (calcCs != cs)
+                    {
+                        throw new PgpException("Checksum mismatch: passphrase wrong, expected "
+							+ cs.ToString("X")
+							+ " found " + calcCs.ToString("X"));
+                    }
+                }
+
+				return data;
+            }
+            catch (PgpException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("Exception decrypting key", e);
+            }
+        }
+
+		/// <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)
+                return null;
+
+			PublicKeyPacket pubPk = secret.PublicKeyPacket;
+            try
+            {
+                byte[] data = ExtractKeyData(passPhrase);
+                BcpgInputStream bcpgIn = BcpgInputStream.Wrap(new MemoryStream(data, false));
+                AsymmetricKeyParameter privateKey;
+                switch (pubPk.Algorithm)
+                {
+                case PublicKeyAlgorithmTag.RsaEncrypt:
+                case PublicKeyAlgorithmTag.RsaGeneral:
+                case PublicKeyAlgorithmTag.RsaSign:
+                    RsaPublicBcpgKey rsaPub = (RsaPublicBcpgKey)pubPk.Key;
+                    RsaSecretBcpgKey rsaPriv = new RsaSecretBcpgKey(bcpgIn);
+                    RsaPrivateCrtKeyParameters rsaPrivSpec = new RsaPrivateCrtKeyParameters(
+                        rsaPriv.Modulus,
+                        rsaPub.PublicExponent,
+                        rsaPriv.PrivateExponent,
+                        rsaPriv.PrimeP,
+                        rsaPriv.PrimeQ,
+                        rsaPriv.PrimeExponentP,
+                        rsaPriv.PrimeExponentQ,
+                        rsaPriv.CrtCoefficient);
+                    privateKey = rsaPrivSpec;
+                    break;
+                case PublicKeyAlgorithmTag.Dsa:
+                    DsaPublicBcpgKey dsaPub = (DsaPublicBcpgKey)pubPk.Key;
+                    DsaSecretBcpgKey dsaPriv = new DsaSecretBcpgKey(bcpgIn);
+                    DsaParameters dsaParams = new DsaParameters(dsaPub.P, dsaPub.Q, dsaPub.G);
+                    privateKey = new DsaPrivateKeyParameters(dsaPriv.X, dsaParams);
+                    break;
+                case PublicKeyAlgorithmTag.ElGamalEncrypt:
+                case PublicKeyAlgorithmTag.ElGamalGeneral:
+                    ElGamalPublicBcpgKey elPub = (ElGamalPublicBcpgKey)pubPk.Key;
+                    ElGamalSecretBcpgKey elPriv = new ElGamalSecretBcpgKey(bcpgIn);
+                    ElGamalParameters elParams = new ElGamalParameters(elPub.P, elPub.G);
+                    privateKey = new ElGamalPrivateKeyParameters(elPriv.X, elParams);
+                    break;
+                default:
+                    throw new PgpException("unknown public key algorithm encountered");
+                }
+
+				return new PgpPrivateKey(privateKey, KeyId);
+            }
+            catch (PgpException e)
+            {
+                throw e;
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("Exception constructing key", e);
+            }
+        }
+
+		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(
+            Stream outStr)
+        {
+            BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+			bcpgOut.WritePacket(secret);
+            if (pub.trustPk != null)
+            {
+                bcpgOut.WritePacket(pub.trustPk);
+            }
+
+			if (pub.subSigs == null) // is not a sub key
+            {
+				foreach (PgpSignature keySig in pub.keySigs)
+				{
+					keySig.Encode(bcpgOut);
+                }
+
+				for (int i = 0; i != pub.ids.Count; i++)
+                {
+					object pubID = pub.ids[i];
+                    if (pubID is string)
+                    {
+                        string id = (string) pubID;
+                        bcpgOut.WritePacket(new UserIdPacket(id));
+                    }
+                    else
+                    {
+                        PgpUserAttributeSubpacketVector v = (PgpUserAttributeSubpacketVector) pubID;
+                        bcpgOut.WritePacket(new UserAttributePacket(v.ToSubpacketArray()));
+                    }
+
+					if (pub.idTrusts[i] != null)
+                    {
+                        bcpgOut.WritePacket((ContainedPacket)pub.idTrusts[i]);
+                    }
+
+					foreach (PgpSignature sig in (IList) pub.idSigs[i])
+					{
+						sig.Encode(bcpgOut);
+                    }
+                }
+            }
+            else
+            {
+				foreach (PgpSignature subSig in pub.subSigs)
+				{
+					subSig.Encode(bcpgOut);
+                }
+            }
+
+			// 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>
+        public static PgpSecretKey CopyWithNewPassword(
+            PgpSecretKey				key,
+            char[]						oldPassPhrase,
+            char[]						newPassPhrase,
+            SymmetricKeyAlgorithmTag	newEncAlgorithm,
+            SecureRandom				rand)
+        {
+            byte[]	rawKeyData = key.ExtractKeyData(oldPassPhrase);
+			int		s2kUsage = key.secret.S2kUsage;
+			byte[]	iv = null;
+            S2k		s2k = null;
+            byte[]	keyData;
+
+			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;
+				}
+			}
+            else
+            {
+                try
+                {
+					keyData = EncryptKeyData(rawKeyData, newEncAlgorithm, newPassPhrase, rand, out s2k, out iv);
+                }
+                catch (PgpException e)
+                {
+                    throw e;
+                }
+                catch (Exception e)
+                {
+                    throw new PgpException("Exception encrypting key", e);
+                }
+            }
+
+			SecretKeyPacket secret;
+            if (key.secret is SecretSubkeyPacket)
+            {
+                secret = new SecretSubkeyPacket(key.secret.PublicKeyPacket,
+					newEncAlgorithm, s2kUsage, s2k, iv, keyData);
+            }
+            else
+            {
+                secret = new SecretKeyPacket(key.secret.PublicKeyPacket,
+	                newEncAlgorithm, s2kUsage, s2k, iv, keyData);
+            }
+
+			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);
+		}
+
+		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
new file mode 100644
index 000000000..3e646eaa1
--- /dev/null
+++ b/Crypto/src/openpgp/PgpSecretKeyRing.cs
@@ -0,0 +1,301 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+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
+    {
+        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(
+            byte[] encoding)
+            : this(new MemoryStream(encoding))
+        {
+        }
+
+		public PgpSecretKeyRing(
+            Stream inputStream)
+        {
+			this.keys = Platform.CreateArrayList();
+            this.extraPubKeys = Platform.CreateArrayList();
+
+			BcpgInputStream bcpgInput = BcpgInputStream.Wrap(inputStream);
+
+			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"));
+            }
+
+			SecretKeyPacket secret = (SecretKeyPacket) bcpgInput.ReadPacket();
+
+			//
+            // ignore GPG comment packets if found.
+            //
+            while (bcpgInput.NextPacketTag() == PacketTag.Experimental2)
+            {
+                bcpgInput.ReadPacket();
+            }
+
+			TrustPacket trust = ReadOptionalTrustPacket(bcpgInput);
+
+			// revocation and direct signatures
+			IList keySigs = ReadSignaturesAndTrust(bcpgInput);
+
+			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)));
+
+
+			// 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));
+				}
+            }
+        }
+
+		/// <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>
+        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()
+        {
+            return new EnumerableProxy(keys);
+        }
+
+        public PgpSecretKey GetSecretKey(
+            long keyId)
+        {
+			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);
+		}
+
+		public byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+
+            Encode(bOut);
+
+            return bOut.ToArray();
+        }
+
+        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);
+			}
+        }
+
+		/// <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)
+		{
+            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(
+            PgpSecretKeyRing  secRing,
+            PgpSecretKey      secKey)
+        {
+            IList keys = Platform.CreateArrayList(secRing.keys);
+            bool found = false;
+			bool masterFound = false;
+
+			for (int i = 0; i != keys.Count; i++)
+            {
+                PgpSecretKey key = (PgpSecretKey) keys[i];
+
+				if (key.KeyId == secKey.KeyId)
+                {
+                    found = true;
+                    keys[i] = secKey;
+                }
+				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);
+				}
+            }
+
+			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>
+        public static PgpSecretKeyRing RemoveSecretKey(
+            PgpSecretKeyRing  secRing,
+            PgpSecretKey      secKey)
+        {
+            IList keys = Platform.CreateArrayList(secRing.keys);
+            bool found = false;
+
+			for (int i = 0; i < keys.Count; i++)
+            {
+                PgpSecretKey key = (PgpSecretKey)keys[i];
+
+				if (key.KeyId == secKey.KeyId)
+                {
+                    found = true;
+                    keys.RemoveAt(i);
+                }
+            }
+
+			return found ? new PgpSecretKeyRing(keys, secRing.extraPubKeys) : null;
+        }
+    }
+}
diff --git a/Crypto/src/openpgp/PgpSecretKeyRingBundle.cs b/Crypto/src/openpgp/PgpSecretKeyRingBundle.cs
new file mode 100644
index 000000000..18636dd65
--- /dev/null
+++ b/Crypto/src/openpgp/PgpSecretKeyRingBundle.cs
@@ -0,0 +1,281 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>
+	/// Often a PGP key ring file is made up of a succession of master/sub-key key rings.
+	/// If you want to read an entire secret key file in one hit this is the class for you.
+	/// </remarks>
+    public class PgpSecretKeyRingBundle
+    {
+        private readonly IDictionary secretRings;
+        private readonly IList order;
+
+		private PgpSecretKeyRingBundle(
+            IDictionary	secretRings,
+            IList       order)
+        {
+            this.secretRings = secretRings;
+            this.order = order;
+        }
+
+		public PgpSecretKeyRingBundle(
+            byte[] encoding)
+            : this(new MemoryStream(encoding, false))
+		{
+        }
+
+		/// <summary>Build a PgpSecretKeyRingBundle from the passed in input stream.</summary>
+		/// <param name="inputStream">Input stream containing data.</param>
+		/// <exception cref="IOException">If a problem parsing the stream occurs.</exception>
+		/// <exception cref="PgpException">If an object is encountered which isn't a PgpSecretKeyRing.</exception>
+		public PgpSecretKeyRingBundle(
+            Stream inputStream)
+			: this(new PgpObjectFactory(inputStream).AllPgpObjects())
+        {
+        }
+
+		public PgpSecretKeyRingBundle(
+            IEnumerable e)
+        {
+			this.secretRings = Platform.CreateHashtable();
+            this.order = Platform.CreateArrayList();
+
+			foreach (object obj in e)
+			{
+				PgpSecretKeyRing pgpSecret = obj as PgpSecretKeyRing;
+
+				if (pgpSecret == null)
+				{
+					throw new PgpException(obj.GetType().FullName + " found where PgpSecretKeyRing expected");
+				}
+
+				long key = pgpSecret.GetPublicKey().KeyId;
+				secretRings.Add(key, pgpSecret);
+				order.Add(key);
+			}
+        }
+
+		[Obsolete("Use 'Count' property instead")]
+		public int Size
+		{
+			get { return order.Count; }
+		}
+
+		/// <summary>Return the number of rings in this collection.</summary>
+		public int Count
+        {
+			get { return order.Count; }
+        }
+
+		/// <summary>Allow enumeration of the secret key rings making up this collection.</summary>
+		public IEnumerable GetKeyRings()
+        {
+            return new EnumerableProxy(secretRings.Values);
+        }
+
+		/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+		/// <param name="userId">The user ID to be matched.</param>
+		/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+		public IEnumerable GetKeyRings(
+			string userId)
+		{
+			return GetKeyRings(userId, false, false);
+		}
+
+		/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+		/// <param name="userId">The user ID to be matched.</param>
+		/// <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+		/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+		public IEnumerable GetKeyRings(
+            string	userId,
+            bool	matchPartial)
+        {
+			return GetKeyRings(userId, matchPartial, false);
+        }
+
+		/// <summary>Allow enumeration of the key rings associated with the passed in userId.</summary>
+		/// <param name="userId">The user ID to be matched.</param>
+		/// <param name="matchPartial">If true, userId need only be a substring of an actual ID string to match.</param>
+		/// <param name="ignoreCase">If true, case is ignored in user ID comparisons.</param>
+		/// <returns>An <c>IEnumerable</c> of key rings which matched (possibly none).</returns>
+		public IEnumerable GetKeyRings(
+			string	userId,
+			bool	matchPartial,
+			bool	ignoreCase)
+		{
+            IList rings = Platform.CreateArrayList();
+
+			if (ignoreCase)
+			{
+				userId = userId.ToLowerInvariant();
+			}
+
+			foreach (PgpSecretKeyRing secRing in GetKeyRings())
+			{
+				foreach (string nextUserID in secRing.GetSecretKey().UserIds)
+				{
+					string next = nextUserID;
+					if (ignoreCase)
+					{
+						next = next.ToLowerInvariant();
+					}
+
+					if (matchPartial)
+					{
+						if (next.IndexOf(userId) > -1)
+						{
+							rings.Add(secRing);
+						}
+					}
+					else
+					{
+						if (next.Equals(userId))
+						{
+							rings.Add(secRing);
+						}
+					}
+				}
+			}
+
+			return new EnumerableProxy(rings);
+		}
+
+		/// <summary>Return the PGP secret key associated with the given key id.</summary>
+		/// <param name="keyId">The ID of the secret key to return.</param>
+		public PgpSecretKey GetSecretKey(
+            long keyId)
+        {
+            foreach (PgpSecretKeyRing secRing in GetKeyRings())
+            {
+                PgpSecretKey sec = secRing.GetSecretKey(keyId);
+
+				if (sec != null)
+                {
+                    return sec;
+                }
+            }
+
+            return null;
+        }
+
+		/// <summary>Return the secret key ring which contains the key referred to by keyId</summary>
+		/// <param name="keyId">The ID of the secret key</param>
+		public PgpSecretKeyRing GetSecretKeyRing(
+            long keyId)
+        {
+            long id = keyId;
+
+            if (secretRings.Contains(id))
+            {
+                return (PgpSecretKeyRing) secretRings[id];
+            }
+
+			foreach (PgpSecretKeyRing secretRing in GetKeyRings())
+            {
+                PgpSecretKey secret = secretRing.GetSecretKey(keyId);
+
+                if (secret != null)
+                {
+                    return secretRing;
+                }
+            }
+
+            return null;
+        }
+
+		/// <summary>
+		/// Return true if a key matching the passed in key ID is present, false otherwise.
+		/// </summary>
+		/// <param name="keyID">key ID to look for.</param>
+		public bool Contains(
+			long keyID)
+		{
+			return GetSecretKey(keyID) != null;
+		}
+
+		public byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+
+			Encode(bOut);
+
+			return bOut.ToArray();
+        }
+
+		public void Encode(
+			Stream outStr)
+        {
+			BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStr);
+
+			foreach (long key in order)
+            {
+                PgpSecretKeyRing pub = (PgpSecretKeyRing) secretRings[key];
+
+				pub.Encode(bcpgOut);
+            }
+        }
+
+		/// <summary>
+		/// Return a new bundle containing the contents of the passed in bundle and
+		/// the passed in secret key ring.
+		/// </summary>
+		/// <param name="bundle">The <c>PgpSecretKeyRingBundle</c> the key ring is to be added to.</param>
+		/// <param name="secretKeyRing">The key ring to be added.</param>
+		/// <returns>A new <c>PgpSecretKeyRingBundle</c> merging the current one with the passed in key ring.</returns>
+		/// <exception cref="ArgumentException">If the keyId for the passed in key ring is already present.</exception>
+        public static PgpSecretKeyRingBundle AddSecretKeyRing(
+            PgpSecretKeyRingBundle  bundle,
+            PgpSecretKeyRing        secretKeyRing)
+        {
+            long key = secretKeyRing.GetPublicKey().KeyId;
+
+            if (bundle.secretRings.Contains(key))
+            {
+                throw new ArgumentException("Collection already contains a key with a keyId for the passed in ring.");
+            }
+
+            IDictionary newSecretRings = Platform.CreateHashtable(bundle.secretRings);
+            IList newOrder = Platform.CreateArrayList(bundle.order);
+
+            newSecretRings[key] = secretKeyRing;
+            newOrder.Add(key);
+
+            return new PgpSecretKeyRingBundle(newSecretRings, newOrder);
+        }
+
+		/// <summary>
+		/// Return a new bundle containing the contents of the passed in bundle with
+		/// the passed in secret key ring removed.
+		/// </summary>
+		/// <param name="bundle">The <c>PgpSecretKeyRingBundle</c> the key ring is to be removed from.</param>
+		/// <param name="secretKeyRing">The key ring to be removed.</param>
+		/// <returns>A new <c>PgpSecretKeyRingBundle</c> not containing the passed in key ring.</returns>
+		/// <exception cref="ArgumentException">If the keyId for the passed in key ring is not present.</exception>
+        public static PgpSecretKeyRingBundle RemoveSecretKeyRing(
+            PgpSecretKeyRingBundle  bundle,
+            PgpSecretKeyRing        secretKeyRing)
+        {
+            long key = secretKeyRing.GetPublicKey().KeyId;
+
+			if (!bundle.secretRings.Contains(key))
+            {
+                throw new ArgumentException("Collection does not contain a key with a keyId for the passed in ring.");
+            }
+
+            IDictionary newSecretRings = Platform.CreateHashtable(bundle.secretRings);
+            IList newOrder = Platform.CreateArrayList(bundle.order);
+
+			newSecretRings.Remove(key);
+			newOrder.Remove(key);
+
+			return new PgpSecretKeyRingBundle(newSecretRings, newOrder);
+        }
+    }
+}
diff --git a/Crypto/src/openpgp/PgpSignature.cs b/Crypto/src/openpgp/PgpSignature.cs
new file mode 100644
index 000000000..cbe0d83b4
--- /dev/null
+++ b/Crypto/src/openpgp/PgpSignature.cs
@@ -0,0 +1,422 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Asn1;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>A PGP signature object.</remarks>
+    public class PgpSignature
+    {
+        public const int BinaryDocument = 0x00;
+        public const int CanonicalTextDocument = 0x01;
+        public const int StandAlone = 0x02;
+
+        public const int DefaultCertification = 0x10;
+        public const int NoCertification = 0x11;
+        public const int CasualCertification = 0x12;
+        public const int PositiveCertification = 0x13;
+
+        public const int SubkeyBinding = 0x18;
+		public const int PrimaryKeyBinding = 0x19;
+		public const int DirectKey = 0x1f;
+        public const int KeyRevocation = 0x20;
+        public const int SubkeyRevocation = 0x28;
+        public const int CertificationRevocation = 0x30;
+        public const int Timestamp = 0x40;
+
+        private readonly SignaturePacket	sigPck;
+        private readonly int				signatureType;
+        private readonly TrustPacket		trustPck;
+
+		private ISigner	sig;
+		private byte	lastb; // Initial value anything but '\r'
+
+		internal PgpSignature(
+            BcpgInputStream bcpgInput)
+            : this((SignaturePacket)bcpgInput.ReadPacket())
+        {
+        }
+
+		internal PgpSignature(
+            SignaturePacket sigPacket)
+			: this(sigPacket, null)
+        {
+        }
+
+        internal PgpSignature(
+            SignaturePacket	sigPacket,
+            TrustPacket		trustPacket)
+        {
+			if (sigPacket == null)
+				throw new ArgumentNullException("sigPacket");
+
+			this.sigPck = sigPacket;
+			this.signatureType = sigPck.SignatureType;
+			this.trustPck = trustPacket;
+        }
+
+		private void GetSig()
+        {
+            this.sig = SignerUtilities.GetSigner(
+				PgpUtilities.GetSignatureName(sigPck.KeyAlgorithm, sigPck.HashAlgorithm));
+        }
+
+		/// <summary>The OpenPGP version number for this signature.</summary>
+		public int Version
+		{
+			get { return sigPck.Version; }
+		}
+
+		/// <summary>The key algorithm associated with this signature.</summary>
+		public PublicKeyAlgorithmTag KeyAlgorithm
+		{
+			get { return sigPck.KeyAlgorithm; }
+		}
+
+		/// <summary>The hash algorithm associated with this signature.</summary>
+		public HashAlgorithmTag HashAlgorithm
+		{
+			get { return sigPck.HashAlgorithm; }
+		}
+
+		public void InitVerify(
+            PgpPublicKey pubKey)
+        {
+			lastb = 0;
+            if (sig == null)
+            {
+                GetSig();
+            }
+            try
+            {
+                sig.Init(false, pubKey.GetKey());
+            }
+            catch (InvalidKeyException e)
+            {
+                throw new PgpException("invalid key.", e);
+            }
+        }
+
+        public void Update(
+            byte b)
+        {
+            if (signatureType == 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(
+            params byte[] bytes)
+        {
+			Update(bytes, 0, bytes.Length);
+        }
+
+		public void Update(
+            byte[]	bytes,
+            int		off,
+            int		length)
+        {
+            if (signatureType == CanonicalTextDocument)
+            {
+                int finish = off + length;
+
+				for (int i = off; i != finish; i++)
+                {
+                    doCanonicalUpdateByte(bytes[i]);
+                }
+            }
+            else
+            {
+                sig.BlockUpdate(bytes, off, length);
+            }
+        }
+
+		public bool Verify()
+        {
+            byte[] trailer = GetSignatureTrailer();
+            sig.BlockUpdate(trailer, 0, trailer.Length);
+
+			return sig.VerifySignature(GetSignature());
+        }
+
+		private void UpdateWithIdData(
+			int		header,
+			byte[]	idBytes)
+		{
+			this.Update(
+				(byte) header,
+				(byte)(idBytes.Length >> 24),
+				(byte)(idBytes.Length >> 16),
+				(byte)(idBytes.Length >> 8),
+				(byte)(idBytes.Length));
+			this.Update(idBytes);
+		}
+
+		private void UpdateWithPublicKey(
+			PgpPublicKey key)
+		{
+			byte[] keyBytes = GetEncodedPublicKey(key);
+
+			this.Update(
+				(byte) 0x99,
+				(byte)(keyBytes.Length >> 8),
+				(byte)(keyBytes.Length));
+			this.Update(keyBytes);
+		}
+
+		/// <summary>
+		/// Verify the signature as certifying the passed in public key as associated
+		/// with the passed in user attributes.
+		/// </summary>
+		/// <param name="userAttributes">User attributes the key was stored under.</param>
+		/// <param name="key">The key to be verified.</param>
+		/// <returns>True, if the signature matches, false otherwise.</returns>
+		public bool VerifyCertification(
+			PgpUserAttributeSubpacketVector	userAttributes,
+			PgpPublicKey					key)
+		{
+			UpdateWithPublicKey(key);
+
+			//
+			// hash in the userAttributes
+			//
+			try
+			{
+				MemoryStream bOut = new MemoryStream();
+				foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray())
+				{
+					packet.Encode(bOut);
+				}
+				UpdateWithIdData(0xd1, bOut.ToArray());
+			}
+			catch (IOException e)
+			{
+				throw new PgpException("cannot encode subpacket array", e);
+			}
+
+			this.Update(sigPck.GetSignatureTrailer());
+
+			return sig.VerifySignature(this.GetSignature());
+		}
+
+		/// <summary>
+		/// Verify the signature as certifying the passed in public key as associated
+		/// with the passed in ID.
+		/// </summary>
+		/// <param name="id">ID the key was stored under.</param>
+		/// <param name="key">The key to be verified.</param>
+		/// <returns>True, if the signature matches, false otherwise.</returns>
+        public bool VerifyCertification(
+            string			id,
+            PgpPublicKey	key)
+        {
+			UpdateWithPublicKey(key);
+
+			//
+            // hash in the id
+            //
+			UpdateWithIdData(0xb4, Strings.ToByteArray(id));
+
+			Update(sigPck.GetSignatureTrailer());
+
+			return sig.VerifySignature(GetSignature());
+        }
+
+		/// <summary>Verify a certification for the passed in key against the passed in master key.</summary>
+		/// <param name="masterKey">The key we are verifying against.</param>
+		/// <param name="pubKey">The key we are verifying.</param>
+		/// <returns>True, if the certification is valid, false otherwise.</returns>
+        public bool VerifyCertification(
+            PgpPublicKey	masterKey,
+            PgpPublicKey	pubKey)
+        {
+			UpdateWithPublicKey(masterKey);
+			UpdateWithPublicKey(pubKey);
+
+			Update(sigPck.GetSignatureTrailer());
+
+			return sig.VerifySignature(GetSignature());
+        }
+
+		/// <summary>Verify a key certification, such as revocation, for the passed in key.</summary>
+		/// <param name="pubKey">The key we are checking.</param>
+		/// <returns>True, if the certification is valid, false otherwise.</returns>
+        public bool VerifyCertification(
+            PgpPublicKey pubKey)
+        {
+            if (SignatureType != KeyRevocation
+                && SignatureType != SubkeyRevocation)
+            {
+                throw new InvalidOperationException("signature is not a key signature");
+            }
+
+			UpdateWithPublicKey(pubKey);
+
+            Update(sigPck.GetSignatureTrailer());
+
+			return sig.VerifySignature(GetSignature());
+        }
+
+		public int SignatureType
+        {
+			get { return sigPck.SignatureType; }
+        }
+
+		/// <summary>The ID of the key that created the signature.</summary>
+        public long KeyId
+        {
+            get { return sigPck.KeyId; }
+        }
+
+		[Obsolete("Use 'CreationTime' property instead")]
+		public DateTime GetCreationTime()
+		{
+			return CreationTime;
+		}
+
+		/// <summary>The creation time of this signature.</summary>
+        public DateTime CreationTime
+        {
+			get { return DateTimeUtilities.UnixMsToDateTime(sigPck.CreationTime); }
+        }
+
+		public byte[] GetSignatureTrailer()
+        {
+            return sigPck.GetSignatureTrailer();
+        }
+
+		/// <summary>
+		/// Return true if the signature has either hashed or unhashed subpackets.
+		/// </summary>
+		public bool HasSubpackets
+		{
+			get
+			{
+				return sigPck.GetHashedSubPackets() != null
+					|| sigPck.GetUnhashedSubPackets() != null;
+			}
+		}
+
+		public PgpSignatureSubpacketVector GetHashedSubPackets()
+        {
+            return createSubpacketVector(sigPck.GetHashedSubPackets());
+        }
+
+		public PgpSignatureSubpacketVector GetUnhashedSubPackets()
+        {
+            return createSubpacketVector(sigPck.GetUnhashedSubPackets());
+        }
+
+		private PgpSignatureSubpacketVector createSubpacketVector(SignatureSubpacket[] pcks)
+		{
+			return pcks == null ? null : new PgpSignatureSubpacketVector(pcks);
+		}
+
+		public byte[] GetSignature()
+        {
+            MPInteger[] sigValues = sigPck.GetSignature();
+            byte[] signature;
+
+			if (sigValues != null)
+			{
+				if (sigValues.Length == 1)    // an RSA signature
+				{
+					signature = sigValues[0].Value.ToByteArrayUnsigned();
+				}
+				else
+				{
+					try
+					{
+						signature = new DerSequence(
+							new DerInteger(sigValues[0].Value),
+							new DerInteger(sigValues[1].Value)).GetEncoded();
+					}
+					catch (IOException e)
+					{
+						throw new PgpException("exception encoding DSA sig.", e);
+					}
+				}
+			}
+			else
+			{
+				signature = sigPck.GetSignatureBytes();
+			}
+
+			return signature;
+        }
+
+		// TODO Handle the encoding stuff by subclassing BcpgObject?
+		public byte[] GetEncoded()
+        {
+            MemoryStream bOut = new MemoryStream();
+
+			Encode(bOut);
+
+			return bOut.ToArray();
+        }
+
+		public void Encode(
+            Stream outStream)
+        {
+            BcpgOutputStream bcpgOut = BcpgOutputStream.Wrap(outStream);
+
+			bcpgOut.WritePacket(sigPck);
+
+			if (trustPck != null)
+            {
+                bcpgOut.WritePacket(trustPck);
+            }
+        }
+
+		private byte[] GetEncodedPublicKey(
+			PgpPublicKey pubKey) 
+		{
+			try
+			{
+				return pubKey.publicPk.GetEncodedContents();
+			}
+			catch (IOException e)
+			{
+				throw new PgpException("exception preparing key.", e);
+			}
+		}
+    }
+}
diff --git a/Crypto/src/openpgp/PgpSignatureGenerator.cs b/Crypto/src/openpgp/PgpSignatureGenerator.cs
new file mode 100644
index 000000000..891397267
--- /dev/null
+++ b/Crypto/src/openpgp/PgpSignatureGenerator.cs
@@ -0,0 +1,393 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Crypto;
+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 PGP signatures.</remarks>
+	// TODO Should be able to implement ISigner?
+    public class PgpSignatureGenerator
+    {
+		private static readonly SignatureSubpacket[] EmptySignatureSubpackets = new SignatureSubpacket[0];
+
+		private PublicKeyAlgorithmTag	keyAlgorithm;
+        private HashAlgorithmTag		hashAlgorithm;
+        private PgpPrivateKey			privKey;
+        private ISigner					sig;
+        private IDigest					dig;
+        private int						signatureType;
+        private byte					lastb;
+
+		private SignatureSubpacket[] unhashed = EmptySignatureSubpackets;
+        private SignatureSubpacket[] hashed = EmptySignatureSubpackets;
+
+		/// <summary>Create a generator for the passed in keyAlgorithm and hashAlgorithm codes.</summary>
+        public PgpSignatureGenerator(
+            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(
+            params byte[] b)
+        {
+			Update(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);
+            }
+        }
+
+		public void SetHashedSubpackets(
+            PgpSignatureSubpacketVector hashedPackets)
+        {
+			hashed = hashedPackets == null
+				?	EmptySignatureSubpackets
+				:	hashedPackets.ToSubpacketArray();
+        }
+
+		public void SetUnhashedSubpackets(
+            PgpSignatureSubpacketVector unhashedPackets)
+        {
+			unhashed = unhashedPackets == null
+				?	EmptySignatureSubpackets
+				:	unhashedPackets.ToSubpacketArray();
+        }
+
+		/// <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 signature object containing the current signature state.</summary>
+        public PgpSignature Generate()
+        {
+			SignatureSubpacket[] hPkts = hashed, unhPkts = unhashed;
+
+			if (!packetPresent(hashed, SignatureSubpacketTag.CreationTime))
+			{
+				hPkts = insertSubpacket(hPkts, new SignatureCreationTime(false, DateTime.UtcNow));
+			}
+
+			if (!packetPresent(hashed, SignatureSubpacketTag.IssuerKeyId)
+				&& !packetPresent(unhashed, SignatureSubpacketTag.IssuerKeyId))
+			{
+				unhPkts = insertSubpacket(unhPkts, new IssuerKeyId(false, privKey.KeyId));
+			}
+
+			int version = 4;
+			byte[] hData;
+
+			try
+            {
+				MemoryStream hOut = new MemoryStream();
+
+				for (int i = 0; i != hPkts.Length; i++)
+				{
+					hPkts[i].Encode(hOut);
+				}
+
+				byte[] data = hOut.ToArray();
+
+				MemoryStream sOut = new MemoryStream(data.Length + 6);
+				sOut.WriteByte((byte)version);
+                sOut.WriteByte((byte)signatureType);
+                sOut.WriteByte((byte)keyAlgorithm);
+                sOut.WriteByte((byte)hashAlgorithm);
+				sOut.WriteByte((byte)(data.Length >> 8));
+                sOut.WriteByte((byte)data.Length);
+                sOut.Write(data, 0, data.Length);
+
+				hData = sOut.ToArray();
+			}
+            catch (IOException e)
+            {
+                throw new PgpException("exception encoding hashed data.", e);
+            }
+
+			sig.BlockUpdate(hData, 0, hData.Length);
+            dig.BlockUpdate(hData, 0, hData.Length);
+
+			hData = new byte[]
+			{
+				(byte) version,
+				0xff,
+				(byte)(hData.Length >> 24),
+				(byte)(hData.Length >> 16),
+				(byte)(hData.Length >> 8),
+				(byte) hData.Length
+			};
+
+			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(signatureType, privKey.KeyId, keyAlgorithm,
+					hashAlgorithm, hPkts, unhPkts, fingerPrint, sigValues));
+        }
+
+		/// <summary>Generate a certification for the passed in ID and key.</summary>
+		/// <param name="id">The ID we are certifying against the public key.</param>
+		/// <param name="pubKey">The key we are certifying against the ID.</param>
+		/// <returns>The certification.</returns>
+        public PgpSignature GenerateCertification(
+            string			id,
+            PgpPublicKey	pubKey)
+        {
+			UpdateWithPublicKey(pubKey);
+
+			//
+            // hash in the id
+            //
+			UpdateWithIdData(0xb4, Strings.ToByteArray(id));
+
+			return Generate();
+        }
+
+		/// <summary>Generate a certification for the passed in userAttributes.</summary>
+		/// <param name="userAttributes">The ID we are certifying against the public key.</param>
+		/// <param name="pubKey">The key we are certifying against the ID.</param>
+		/// <returns>The certification.</returns>
+		public PgpSignature GenerateCertification(
+			PgpUserAttributeSubpacketVector	userAttributes,
+			PgpPublicKey					pubKey)
+		{
+			UpdateWithPublicKey(pubKey);
+
+			//
+			// hash in the attributes
+			//
+			try
+			{
+				MemoryStream bOut = new MemoryStream();
+				foreach (UserAttributeSubpacket packet in userAttributes.ToSubpacketArray())
+				{
+					packet.Encode(bOut);
+				}
+				UpdateWithIdData(0xd1, bOut.ToArray());
+			}
+			catch (IOException e)
+			{
+				throw new PgpException("cannot encode subpacket array", e);
+			}
+
+			return this.Generate();
+		}
+
+		/// <summary>Generate a certification for the passed in key against the passed in master key.</summary>
+		/// <param name="masterKey">The key we are certifying against.</param>
+		/// <param name="pubKey">The key we are certifying.</param>
+		/// <returns>The certification.</returns>
+        public PgpSignature GenerateCertification(
+            PgpPublicKey	masterKey,
+            PgpPublicKey	pubKey)
+        {
+			UpdateWithPublicKey(masterKey);
+			UpdateWithPublicKey(pubKey);
+
+			return Generate();
+        }
+
+		/// <summary>Generate a certification, such as a revocation, for the passed in key.</summary>
+		/// <param name="pubKey">The key we are certifying.</param>
+		/// <returns>The certification.</returns>
+        public PgpSignature GenerateCertification(
+            PgpPublicKey pubKey)
+        {
+			UpdateWithPublicKey(pubKey);
+
+			return Generate();
+        }
+
+		private byte[] GetEncodedPublicKey(
+			PgpPublicKey pubKey) 
+		{
+			try
+			{
+				return pubKey.publicPk.GetEncodedContents();
+			}
+			catch (IOException e)
+			{
+				throw new PgpException("exception preparing key.", e);
+			}
+		}
+
+		private bool packetPresent(
+			SignatureSubpacket[]	packets,
+			SignatureSubpacketTag	type)
+		{
+			for (int i = 0; i != packets.Length; i++)
+			{
+				if (packets[i].SubpacketType == type)
+				{
+					return true;
+				}
+			}
+
+			return false;
+		}
+
+		private SignatureSubpacket[] insertSubpacket(
+			SignatureSubpacket[]	packets,
+			SignatureSubpacket		subpacket)
+		{
+			SignatureSubpacket[] tmp = new SignatureSubpacket[packets.Length + 1];
+			tmp[0] = subpacket;
+			packets.CopyTo(tmp, 1);
+			return tmp;
+		}
+
+		private void UpdateWithIdData(
+			int		header,
+			byte[]	idBytes)
+		{
+			this.Update(
+				(byte) header,
+				(byte)(idBytes.Length >> 24),
+				(byte)(idBytes.Length >> 16),
+				(byte)(idBytes.Length >> 8),
+				(byte)(idBytes.Length));
+			this.Update(idBytes);
+		}
+
+		private void UpdateWithPublicKey(
+			PgpPublicKey key)
+		{
+			byte[] keyBytes = GetEncodedPublicKey(key);
+
+			this.Update(
+				(byte) 0x99,
+				(byte)(keyBytes.Length >> 8),
+				(byte)(keyBytes.Length));
+			this.Update(keyBytes);
+		}
+	}
+}
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
new file mode 100644
index 000000000..e22381bb1
--- /dev/null
+++ b/Crypto/src/openpgp/PgpUtilities.cs
@@ -0,0 +1,428 @@
+using System;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+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.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+	/// <remarks>Basic utility class.</remarks>
+    public sealed class PgpUtilities
+    {
+        private PgpUtilities()
+        {
+        }
+
+		public static MPInteger[] DsaSigToMpi(
+			byte[] encoding)
+		{
+			DerInteger i1, i2;
+
+			try
+			{
+				Asn1Sequence s = (Asn1Sequence) Asn1Object.FromByteArray(encoding);
+
+				i1 = (DerInteger) s[0];
+				i2 = (DerInteger) s[1];
+			}
+			catch (IOException e)
+			{
+				throw new PgpException("exception encoding signature", e);
+			}
+
+			return new MPInteger[]{ new MPInteger(i1.Value), new MPInteger(i2.Value) };
+		}
+
+		public static MPInteger[] RsaSigToMpi(
+			byte[] encoding)
+		{
+			return new MPInteger[]{ new MPInteger(new BigInteger(1, encoding)) };
+		}
+
+		public static string GetDigestName(
+            HashAlgorithmTag hashAlgorithm)
+        {
+            switch (hashAlgorithm)
+            {
+				case HashAlgorithmTag.Sha1:
+					return "SHA1";
+				case HashAlgorithmTag.MD2:
+					return "MD2";
+				case HashAlgorithmTag.MD5:
+					return "MD5";
+				case HashAlgorithmTag.RipeMD160:
+					return "RIPEMD160";
+				case HashAlgorithmTag.Sha224:
+					return "SHA224";
+				case HashAlgorithmTag.Sha256:
+					return "SHA256";
+				case HashAlgorithmTag.Sha384:
+					return "SHA384";
+				case HashAlgorithmTag.Sha512:
+					return "SHA512";
+				default:
+					throw new PgpException("unknown hash algorithm tag in GetDigestName: " + hashAlgorithm);
+			}
+        }
+
+		public static string GetSignatureName(
+            PublicKeyAlgorithmTag	keyAlgorithm,
+            HashAlgorithmTag		hashAlgorithm)
+        {
+            string encAlg;
+			switch (keyAlgorithm)
+            {
+				case PublicKeyAlgorithmTag.RsaGeneral:
+				case PublicKeyAlgorithmTag.RsaSign:
+					encAlg = "RSA";
+					break;
+				case PublicKeyAlgorithmTag.Dsa:
+					encAlg = "DSA";
+					break;
+				case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases.
+				case PublicKeyAlgorithmTag.ElGamalGeneral:
+					encAlg = "ElGamal";
+					break;
+				default:
+					throw new PgpException("unknown algorithm tag in signature:" + keyAlgorithm);
+            }
+
+			return GetDigestName(hashAlgorithm) + "with" + encAlg;
+        }
+
+		public static string GetSymmetricCipherName(
+            SymmetricKeyAlgorithmTag algorithm)
+        {
+            switch (algorithm)
+            {
+				case SymmetricKeyAlgorithmTag.Null:
+					return null;
+				case SymmetricKeyAlgorithmTag.TripleDes:
+					return "DESEDE";
+				case SymmetricKeyAlgorithmTag.Idea:
+					return "IDEA";
+				case SymmetricKeyAlgorithmTag.Cast5:
+					return "CAST5";
+				case SymmetricKeyAlgorithmTag.Blowfish:
+					return "Blowfish";
+				case SymmetricKeyAlgorithmTag.Safer:
+					return "SAFER";
+				case SymmetricKeyAlgorithmTag.Des:
+					return "DES";
+				case SymmetricKeyAlgorithmTag.Aes128:
+					return "AES";
+				case SymmetricKeyAlgorithmTag.Aes192:
+					return "AES";
+				case SymmetricKeyAlgorithmTag.Aes256:
+					return "AES";
+				case SymmetricKeyAlgorithmTag.Twofish:
+					return "Twofish";
+				default:
+					throw new PgpException("unknown symmetric algorithm: " + algorithm);
+            }
+        }
+
+		public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
+        {
+            int keySize;
+            switch (algorithm)
+            {
+                case SymmetricKeyAlgorithmTag.Des:
+                    keySize = 64;
+                    break;
+                case SymmetricKeyAlgorithmTag.Idea:
+                case SymmetricKeyAlgorithmTag.Cast5:
+                case SymmetricKeyAlgorithmTag.Blowfish:
+                case SymmetricKeyAlgorithmTag.Safer:
+                case SymmetricKeyAlgorithmTag.Aes128:
+                    keySize = 128;
+                    break;
+                case SymmetricKeyAlgorithmTag.TripleDes:
+                case SymmetricKeyAlgorithmTag.Aes192:
+                    keySize = 192;
+                    break;
+                case SymmetricKeyAlgorithmTag.Aes256:
+                case SymmetricKeyAlgorithmTag.Twofish:
+                    keySize = 256;
+                    break;
+                default:
+                    throw new PgpException("unknown symmetric algorithm: " + algorithm);
+            }
+
+			return keySize;
+        }
+
+		public static KeyParameter MakeKey(
+			SymmetricKeyAlgorithmTag	algorithm,
+			byte[]						keyBytes)
+		{
+			string algName = GetSymmetricCipherName(algorithm);
+
+			return ParameterUtilities.CreateKeyParameter(algName, keyBytes);
+		}
+
+		public static KeyParameter MakeRandomKey(
+            SymmetricKeyAlgorithmTag	algorithm,
+            SecureRandom				random)
+        {
+            int keySize = GetKeySize(algorithm);
+            byte[] keyBytes = new byte[(keySize + 7) / 8];
+            random.NextBytes(keyBytes);
+			return MakeKey(algorithm, keyBytes);
+        }
+
+		public static KeyParameter MakeKeyFromPassPhrase(
+            SymmetricKeyAlgorithmTag	algorithm,
+            S2k							s2k,
+            char[]						passPhrase)
+        {
+			int keySize = GetKeySize(algorithm);
+			byte[] pBytes = Strings.ToByteArray(new string(passPhrase));
+			byte[] keyBytes = new byte[(keySize + 7) / 8];
+
+			int generatedBytes = 0;
+            int loopCount = 0;
+
+			while (generatedBytes < keyBytes.Length)
+            {
+				IDigest digest;
+				if (s2k != null)
+                {
+					string digestName = GetDigestName(s2k.HashAlgorithm);
+
+                    try
+                    {
+						digest = DigestUtilities.GetDigest(digestName);
+                    }
+                    catch (Exception e)
+                    {
+                        throw new PgpException("can't find S2k digest", e);
+                    }
+
+					for (int i = 0; i != loopCount; i++)
+                    {
+                        digest.Update(0);
+                    }
+
+					byte[] iv = s2k.GetIV();
+
+					switch (s2k.Type)
+                    {
+						case S2k.Simple:
+							digest.BlockUpdate(pBytes, 0, pBytes.Length);
+							break;
+						case S2k.Salted:
+							digest.BlockUpdate(iv, 0, iv.Length);
+							digest.BlockUpdate(pBytes, 0, pBytes.Length);
+							break;
+						case S2k.SaltedAndIterated:
+							long count = s2k.IterationCount;
+							digest.BlockUpdate(iv, 0, iv.Length);
+							digest.BlockUpdate(pBytes, 0, pBytes.Length);
+
+							count -= iv.Length + pBytes.Length;
+
+							while (count > 0)
+							{
+								if (count < iv.Length)
+								{
+									digest.BlockUpdate(iv, 0, (int)count);
+									break;
+								}
+								else
+								{
+									digest.BlockUpdate(iv, 0, iv.Length);
+									count -= iv.Length;
+								}
+
+								if (count < pBytes.Length)
+								{
+									digest.BlockUpdate(pBytes, 0, (int)count);
+									count = 0;
+								}
+								else
+								{
+									digest.BlockUpdate(pBytes, 0, pBytes.Length);
+									count -= pBytes.Length;
+								}
+							}
+							break;
+						default:
+							throw new PgpException("unknown S2k type: " + s2k.Type);
+                    }
+                }
+                else
+                {
+                    try
+                    {
+                        digest = DigestUtilities.GetDigest("MD5");
+
+						for (int i = 0; i != loopCount; i++)
+                        {
+                            digest.Update(0);
+                        }
+
+						digest.BlockUpdate(pBytes, 0, pBytes.Length);
+                    }
+                    catch (Exception e)
+                    {
+                        throw new PgpException("can't find MD5 digest", e);
+                    }
+                }
+
+				byte[] dig = DigestUtilities.DoFinal(digest);
+
+				if (dig.Length > (keyBytes.Length - generatedBytes))
+                {
+                    Array.Copy(dig, 0, keyBytes, generatedBytes, keyBytes.Length - generatedBytes);
+                }
+                else
+                {
+                    Array.Copy(dig, 0, keyBytes, generatedBytes, dig.Length);
+                }
+
+				generatedBytes += dig.Length;
+
+				loopCount++;
+            }
+
+			Array.Clear(pBytes, 0, pBytes.Length);
+
+			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,
+            char		fileType,
+            FileInfo	file)
+        {
+            PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator();
+			Stream pOut = lData.Open(output, fileType, file.Name, file.Length, file.LastWriteTime);
+			PipeFileContents(file, pOut, 4096);
+        }
+
+		/// <summary>Write out the passed in file as a literal data packet in partial packet format.</summary>
+        public static void WriteFileToLiteralData(
+            Stream		output,
+            char		fileType,
+            FileInfo	file,
+            byte[]		buffer)
+        {
+            PgpLiteralDataGenerator lData = new PgpLiteralDataGenerator();
+            Stream pOut = lData.Open(output, fileType, file.Name, file.LastWriteTime, buffer);
+			PipeFileContents(file, pOut, buffer.Length);
+        }
+
+		private static void PipeFileContents(FileInfo file, Stream pOut, int bufSize)
+		{
+			FileStream inputStream = file.OpenRead();
+			byte[] buf = new byte[bufSize];
+
+			int len;
+            while ((len = inputStream.Read(buf, 0, buf.Length)) > 0)
+            {
+                pOut.Write(buf, 0, len);
+            }
+
+			pOut.Close();
+			inputStream.Close();
+		}
+#endif
+
+		private const int ReadAhead = 60;
+
+		private static bool IsPossiblyBase64(
+            int ch)
+        {
+            return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')
+                    || (ch >= '0' && ch <= '9') || (ch == '+') || (ch == '/')
+                    || (ch == '\r') || (ch == '\n');
+        }
+
+		/// <summary>
+		/// Return either an ArmoredInputStream or a BcpgInputStream based on whether
+		/// the initial characters of the stream are binary PGP encodings or not.
+		/// </summary>
+        public static Stream GetDecoderStream(
+            Stream inputStream)
+        {
+			// TODO Remove this restriction?
+			if (!inputStream.CanSeek)
+				throw new ArgumentException("inputStream must be seek-able", "inputStream");
+
+			long markedPos = inputStream.Position;
+
+			int ch = inputStream.ReadByte();
+            if ((ch & 0x80) != 0)
+            {
+                inputStream.Position = markedPos;
+
+				return inputStream;
+            }
+            else
+            {
+                if (!IsPossiblyBase64(ch))
+                {
+                    inputStream.Position = markedPos;
+
+					return new ArmoredInputStream(inputStream);
+                }
+
+				byte[]	buf = new byte[ReadAhead];
+                int		count = 1;
+                int		index = 1;
+
+				buf[0] = (byte)ch;
+                while (count != ReadAhead && (ch = inputStream.ReadByte()) >= 0)
+                {
+                    if (!IsPossiblyBase64(ch))
+                    {
+                        inputStream.Position = markedPos;
+
+						return new ArmoredInputStream(inputStream);
+                    }
+
+					if (ch != '\n' && ch != '\r')
+                    {
+                        buf[index++] = (byte)ch;
+                    }
+
+					count++;
+                }
+
+				inputStream.Position = markedPos;
+
+				//
+                // nothing but new lines, little else, assume regular armoring
+                //
+                if (count < 4)
+                {
+                    return new ArmoredInputStream(inputStream);
+                }
+
+				//
+                // test our non-blank data
+                //
+                byte[] firstBlock = new byte[8];
+				Array.Copy(buf, 0, firstBlock, 0, firstBlock.Length);
+				byte[] decoded = Base64.Decode(firstBlock);
+
+				//
+                // it's a base64 PGP block.
+                //
+				bool hasHeaders = (decoded[0] & 0x80) == 0;
+
+				return new ArmoredInputStream(inputStream, hasHeaders);
+            }
+        }
+    }
+}
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
new file mode 100644
index 000000000..baad0d429
--- /dev/null
+++ b/Crypto/src/openpgp/WrappedGeneratorStream.cs
@@ -0,0 +1,28 @@
+using System.IO;
+
+using Org.BouncyCastle.Asn1.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+    public class WrappedGeneratorStream
+        : FilterStream
+    {
+        private readonly IStreamGenerator gen;
+
+        public WrappedGeneratorStream(
+            IStreamGenerator gen,
+            Stream str)
+            : base(str)
+        {
+            this.gen = gen;
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                gen.Close();
+            }
+        }
+    }
+}
diff --git a/Crypto/src/openssl/EncryptionException.cs b/Crypto/src/openssl/EncryptionException.cs
new file mode 100644
index 000000000..043e8f899
--- /dev/null
+++ b/Crypto/src/openssl/EncryptionException.cs
@@ -0,0 +1,22 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Security
+{
+	public class EncryptionException
+		: IOException
+	{
+		public EncryptionException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public EncryptionException(
+			string		message,
+			Exception	exception)
+			: base(message, exception)
+		{
+		}
+	}
+}
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
new file mode 100644
index 000000000..a1f64498d
--- /dev/null
+++ b/Crypto/src/openssl/MiscPemGenerator.cs
@@ -0,0 +1,277 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+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.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO.Pem;
+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);
+		}
+
+//		private string GetHexEncoded(byte[] bytes)
+//		{
+//			bytes = Hex.Encode(bytes);
+//
+//			char[] chars = new char[bytes.Length];
+//
+//			for (int i = 0; i != bytes.Length; i++)
+//			{
+//				chars[i] = (char)bytes[i];
+//			}
+//
+//			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);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/openssl/PEMException.cs b/Crypto/src/openssl/PEMException.cs
new file mode 100644
index 000000000..df0eebc69
--- /dev/null
+++ b/Crypto/src/openssl/PEMException.cs
@@ -0,0 +1,22 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.OpenSsl
+{
+	public class PemException
+		: IOException
+	{
+		public PemException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public PemException(
+			string		message,
+			Exception	exception)
+			: base(message, exception)
+		{
+		}
+	}
+}
diff --git a/Crypto/src/openssl/PEMReader.cs b/Crypto/src/openssl/PEMReader.cs
new file mode 100644
index 000000000..a2fedab96
--- /dev/null
+++ b/Crypto/src/openssl/PEMReader.cs
@@ -0,0 +1,407 @@
+using System;
+using System.Collections;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+using Org.BouncyCastle.Asn1.TeleTrust;
+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.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.IO.Pem;
+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
+	{
+//		private static readonly IDictionary parsers = new Hashtable();
+
+		static PemReader()
+		{
+//			parsers.Add("CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
+//			parsers.Add("NEW CERTIFICATE REQUEST", new PKCS10CertificationRequestParser());
+//			parsers.Add("CERTIFICATE", new X509CertificateParser(provider));
+//			parsers.Add("X509 CERTIFICATE", new X509CertificateParser(provider));
+//			parsers.Add("X509 CRL", new X509CRLParser(provider));
+//			parsers.Add("PKCS7", new PKCS7Parser());
+//			parsers.Add("ATTRIBUTE CERTIFICATE", new X509AttributeCertificateParser());
+//			parsers.Add("EC PARAMETERS", new ECNamedCurveSpecParser());
+//			parsers.Add("PUBLIC KEY", new PublicKeyParser(provider));
+//			parsers.Add("RSA PUBLIC KEY", new RSAPublicKeyParser(provider));
+//			parsers.Add("RSA PRIVATE KEY", new RSAKeyPairParser(provider));
+//			parsers.Add("DSA PRIVATE KEY", new DSAKeyPairParser(provider));
+//			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?
+//			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(
+//		private X9ECParameters ReadECParameters(PemObject pemObject)
+//		{
+//			DerObjectIdentifier oid = (DerObjectIdentifier)Asn1Object.FromByteArray(pemObject.Content);
+//
+//			//return ECNamedCurveTable.getParameterSpec(oid.Id);
+//			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;
+		}
+	}
+}
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
new file mode 100644
index 000000000..b21dee231
--- /dev/null
+++ b/Crypto/src/openssl/PasswordException.cs
@@ -0,0 +1,22 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Security
+{
+	public class PasswordException
+		: IOException
+	{
+		public PasswordException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public PasswordException(
+			string		message,
+			Exception	exception)
+			: base(message, exception)
+		{
+		}
+	}
+}
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
new file mode 100644
index 000000000..6da3ade3e
--- /dev/null
+++ b/Crypto/src/pkcs/AsymmetricKeyEntry.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pkcs
+{
+    public class AsymmetricKeyEntry
+        : Pkcs12Entry
+    {
+        private readonly AsymmetricKeyParameter key;
+
+		public AsymmetricKeyEntry(
+            AsymmetricKeyParameter key)
+			: base(Platform.CreateHashtable())
+        {
+            this.key = key;
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public AsymmetricKeyEntry(
+            AsymmetricKeyParameter key,
+            Hashtable attributes)
+			: base(attributes)
+        {
+            this.key = key;
+        }
+#endif
+
+        public AsymmetricKeyEntry(
+            AsymmetricKeyParameter  key,
+            IDictionary             attributes)
+			: base(attributes)
+        {
+            this.key = key;
+        }
+
+		public AsymmetricKeyParameter Key
+        {
+            get { return this.key; }
+        }
+
+		public override bool Equals(object obj)
+		{
+			AsymmetricKeyEntry other = obj as AsymmetricKeyEntry;
+
+			if (other == null)
+				return false;
+
+			return key.Equals(other.key);
+		}
+
+		public override int GetHashCode()
+		{
+			return ~key.GetHashCode();
+		}
+	}
+}
diff --git a/Crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs b/Crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
new file mode 100644
index 000000000..b69693490
--- /dev/null
+++ b/Crypto/src/pkcs/EncryptedPrivateKeyInfoFactory.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pkcs
+{
+    public sealed class EncryptedPrivateKeyInfoFactory
+    {
+        private EncryptedPrivateKeyInfoFactory()
+        {
+        }
+
+        public static EncryptedPrivateKeyInfo CreateEncryptedPrivateKeyInfo(
+            DerObjectIdentifier		algorithm,
+            char[]					passPhrase,
+            byte[]					salt,
+            int						iterationCount,
+            AsymmetricKeyParameter	key)
+        {
+            return CreateEncryptedPrivateKeyInfo(
+				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,
+            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);
+
+			DerObjectIdentifier oid = PbeUtilities.GetObjectIdentifier(algorithm);
+			AlgorithmIdentifier algID = new AlgorithmIdentifier(oid, parameters);
+
+			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
new file mode 100644
index 000000000..2c343c0b4
--- /dev/null
+++ b/Crypto/src/pkcs/Pkcs10CertificationRequest.cs
@@ -0,0 +1,466 @@
+using System;
+using System.Collections;
+using System.Globalization;
+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.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkcs
+{
+	/// <remarks>
+	/// A class for verifying and creating Pkcs10 Certification requests.
+	/// </remarks>
+	/// <code>
+	/// CertificationRequest ::= Sequence {
+	///   certificationRequestInfo  CertificationRequestInfo,
+	///   signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+	///   signature                 BIT STRING
+	/// }
+	///
+	/// CertificationRequestInfo ::= Sequence {
+	///   version             Integer { v1(0) } (v1,...),
+	///   subject             Name,
+	///   subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+	///   attributes          [0] Attributes{{ CRIAttributes }}
+	///  }
+	///
+	///  Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }}
+	///
+	///  Attr { ATTRIBUTE:IOSet } ::= Sequence {
+	///    type    ATTRIBUTE.&amp;id({IOSet}),
+	///    values  Set SIZE(1..MAX) OF ATTRIBUTE.&amp;Type({IOSet}{\@type})
+	///  }
+	/// </code>
+	/// see <a href="http://www.rsasecurity.com/rsalabs/node.asp?id=2132"/>
+	public class Pkcs10CertificationRequest
+		: CertificationRequest
+	{
+		protected static readonly IDictionary algorithms = Platform.CreateHashtable();
+        protected static readonly IDictionary exParams = Platform.CreateHashtable();
+        protected static readonly IDictionary keyAlgorithms = Platform.CreateHashtable();
+        protected static readonly IDictionary oids = Platform.CreateHashtable();
+		protected static readonly ISet noParams = new HashSet();
+
+		static Pkcs10CertificationRequest()
+		{
+			algorithms.Add("MD2WITHRSAENCRYPTION", new DerObjectIdentifier("1.2.840.113549.1.1.2"));
+			algorithms.Add("MD2WITHRSA", new DerObjectIdentifier("1.2.840.113549.1.1.2"));
+			algorithms.Add("MD5WITHRSAENCRYPTION", new DerObjectIdentifier("1.2.840.113549.1.1.4"));
+			algorithms.Add("MD5WITHRSA", new DerObjectIdentifier("1.2.840.113549.1.1.4"));
+			algorithms.Add("RSAWITHMD5", new DerObjectIdentifier("1.2.840.113549.1.1.4"));
+			algorithms.Add("SHA1WITHRSAENCRYPTION", new DerObjectIdentifier("1.2.840.113549.1.1.5"));
+			algorithms.Add("SHA1WITHRSA", new DerObjectIdentifier("1.2.840.113549.1.1.5"));
+			algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+			algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+			algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+			algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+			algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+			algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+			algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+			algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+			algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("RSAWITHSHA1", new DerObjectIdentifier("1.2.840.113549.1.1.5"));
+			algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+			algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+			algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+			algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+			algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+			algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+			algorithms.Add("SHA1WITHDSA", new DerObjectIdentifier("1.2.840.10040.4.3"));
+			algorithms.Add("DSAWITHSHA1", new DerObjectIdentifier("1.2.840.10040.4.3"));
+			algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+			algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+			algorithms.Add("SHA384WITHDSA", NistObjectIdentifiers.DsaWithSha384);
+			algorithms.Add("SHA512WITHDSA", NistObjectIdentifiers.DsaWithSha512);
+			algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+			algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+			algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+			algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+			algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+			algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+			algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+			algorithms.Add("GOST3410WITHGOST3411", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+			algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+			algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+			algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+			//
+			// reverse mappings
+			//
+			oids.Add(new DerObjectIdentifier("1.2.840.113549.1.1.5"), "SHA1WITHRSA");
+			oids.Add(PkcsObjectIdentifiers.Sha224WithRsaEncryption, "SHA224WITHRSA");
+			oids.Add(PkcsObjectIdentifiers.Sha256WithRsaEncryption, "SHA256WITHRSA");
+			oids.Add(PkcsObjectIdentifiers.Sha384WithRsaEncryption, "SHA384WITHRSA");
+			oids.Add(PkcsObjectIdentifiers.Sha512WithRsaEncryption, "SHA512WITHRSA");
+			oids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, "GOST3411WITHGOST3410");
+			oids.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001, "GOST3411WITHECGOST3410");
+
+			oids.Add(new DerObjectIdentifier("1.2.840.113549.1.1.4"), "MD5WITHRSA");
+			oids.Add(new DerObjectIdentifier("1.2.840.113549.1.1.2"), "MD2WITHRSA");
+			oids.Add(new DerObjectIdentifier("1.2.840.10040.4.3"), "SHA1WITHDSA");
+			oids.Add(X9ObjectIdentifiers.ECDsaWithSha1, "SHA1WITHECDSA");
+			oids.Add(X9ObjectIdentifiers.ECDsaWithSha224, "SHA224WITHECDSA");
+			oids.Add(X9ObjectIdentifiers.ECDsaWithSha256, "SHA256WITHECDSA");
+			oids.Add(X9ObjectIdentifiers.ECDsaWithSha384, "SHA384WITHECDSA");
+			oids.Add(X9ObjectIdentifiers.ECDsaWithSha512, "SHA512WITHECDSA");
+			oids.Add(OiwObjectIdentifiers.Sha1WithRsa, "SHA1WITHRSA");
+			oids.Add(OiwObjectIdentifiers.DsaWithSha1, "SHA1WITHDSA");
+			oids.Add(NistObjectIdentifiers.DsaWithSha224, "SHA224WITHDSA");
+			oids.Add(NistObjectIdentifiers.DsaWithSha256, "SHA256WITHDSA");
+
+			//
+			// key types
+			//
+			keyAlgorithms.Add(PkcsObjectIdentifiers.RsaEncryption, "RSA");
+			keyAlgorithms.Add(X9ObjectIdentifiers.IdDsa, "DSA");
+
+			//
+			// According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+			// The parameters field SHALL be NULL for RSA based signature algorithms.
+			//
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+			noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+			noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+			noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+
+			//
+			// RFC 4491
+			//
+			noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+			noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+			//
+			// explicit params
+			//
+			AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+			exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20));
+
+			AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance);
+			exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28));
+
+			AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance);
+			exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32));
+
+			AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance);
+			exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48));
+
+			AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance);
+			exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64));
+		}
+
+		private static RsassaPssParameters CreatePssParams(
+			AlgorithmIdentifier	hashAlgId,
+			int					saltSize)
+		{
+			return new RsassaPssParameters(
+				hashAlgId,
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId),
+				new DerInteger(saltSize),
+				new DerInteger(1));
+		}
+
+		protected Pkcs10CertificationRequest()
+		{
+		}
+
+		public Pkcs10CertificationRequest(
+			byte[] encoded)
+			: base((Asn1Sequence) Asn1Object.FromByteArray(encoded))
+		{
+		}
+
+		public Pkcs10CertificationRequest(
+			Asn1Sequence seq)
+			: base(seq)
+		{
+		}
+
+		public Pkcs10CertificationRequest(
+			Stream input)
+			: base((Asn1Sequence) Asn1Object.FromStream(input))
+		{
+		}
+
+		/// <summary>
+		/// Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+		/// </summary>
+		///<param name="signatureAlgorithm">Name of Sig Alg.</param>
+		/// <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param>
+		/// <param name="publicKey">Public Key to be included in cert reqest.</param>
+		/// <param name="attributes">ASN1Set of Attributes.</param>
+		/// <param name="signingKey">Matching Private key for nominated (above) public key to be used to sign the request.</param>
+		public Pkcs10CertificationRequest(
+			string					signatureAlgorithm,
+			X509Name				subject,
+			AsymmetricKeyParameter	publicKey,
+			Asn1Set					attributes,
+			AsymmetricKeyParameter	signingKey)
+		{
+			if (signatureAlgorithm == null)
+				throw new ArgumentNullException("signatureAlgorithm");
+			if (subject == null)
+				throw new ArgumentNullException("subject");
+			if (publicKey == null)
+				throw new ArgumentNullException("publicKey");
+			if (publicKey.IsPrivate)
+				throw new ArgumentException("expected public key", "publicKey");
+			if (!signingKey.IsPrivate)
+				throw new ArgumentException("key for signing must be private", "signingKey");
+
+//			DerObjectIdentifier sigOid = SignerUtilities.GetObjectIdentifier(signatureAlgorithm);
+			string algorithmName = signatureAlgorithm.ToUpperInvariant();
+			DerObjectIdentifier sigOid = (DerObjectIdentifier) algorithms[algorithmName];
+
+			if (sigOid == null)
+			{
+				try
+				{
+					sigOid = new DerObjectIdentifier(algorithmName);
+				}
+				catch (Exception e)
+				{
+					throw new ArgumentException("Unknown signature type requested", e);
+				}
+			}
+
+			if (noParams.Contains(sigOid))
+			{
+				this.sigAlgId = new AlgorithmIdentifier(sigOid);
+			}
+			else if (exParams.Contains(algorithmName))
+			{
+				this.sigAlgId = new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
+			}
+			else
+			{
+				this.sigAlgId = new AlgorithmIdentifier(sigOid, DerNull.Instance);
+			}
+
+			SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+
+			this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes);
+
+			ISigner sig = SignerUtilities.GetSigner(signatureAlgorithm);
+
+			sig.Init(true, signingKey);
+
+			try
+			{
+				// Encode.
+				byte[] b = reqInfo.GetDerEncoded();
+				sig.BlockUpdate(b, 0, b.Length);
+			}
+			catch (Exception e)
+			{
+				throw new ArgumentException("exception encoding TBS cert request", e);
+			}
+
+			// Generate Signature.
+			sigBits = new DerBitString(sig.GenerateSignature());
+		}
+
+//        internal Pkcs10CertificationRequest(
+//        	Asn1InputStream seqStream)
+//        {
+//			Asn1Sequence seq = (Asn1Sequence) seqStream.ReadObject();
+//            try
+//            {
+//                this.reqInfo = CertificationRequestInfo.GetInstance(seq[0]);
+//                this.sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]);
+//                this.sigBits = (DerBitString) seq[2];
+//            }
+//            catch (Exception ex)
+//            {
+//                throw new ArgumentException("Create From Asn1Sequence: " + ex.Message);
+//            }
+//        }
+
+		/// <summary>
+		/// Get the public key.
+		/// </summary>
+		/// <returns>The public key.</returns>
+		public AsymmetricKeyParameter GetPublicKey()
+		{
+			return PublicKeyFactory.CreateKey(reqInfo.SubjectPublicKeyInfo);
+		}
+
+		/// <summary>
+		/// Verify Pkcs10 Cert Request is valid.
+		/// </summary>
+		/// <returns>true = valid.</returns>
+		public bool Verify()
+		{
+			return Verify(this.GetPublicKey());
+		}
+
+		public bool Verify(
+			AsymmetricKeyParameter publicKey)
+		{
+			ISigner sig;
+
+			try
+			{
+				sig = SignerUtilities.GetSigner(GetSignatureName(sigAlgId));
+			}
+			catch (Exception e)
+			{
+				// try an alternate
+				string alt = (string) oids[sigAlgId.ObjectID];
+
+				if (alt != null)
+				{
+					sig = SignerUtilities.GetSigner(alt);
+				}
+				else
+				{
+					throw e;
+				}
+			}
+
+			SetSignatureParameters(sig, sigAlgId.Parameters);
+
+			sig.Init(false, publicKey);
+
+			try
+			{
+				byte[] b = reqInfo.GetDerEncoded();
+				sig.BlockUpdate(b, 0, b.Length);
+			}
+			catch (Exception e)
+			{
+				throw new SignatureException("exception encoding TBS cert request", e);
+			}
+
+			return sig.VerifySignature(sigBits.GetBytes());
+		}
+
+//        /// <summary>
+//        /// Get the Der Encoded Pkcs10 Certification Request.
+//        /// </summary>
+//        /// <returns>A byte array.</returns>
+//        public byte[] GetEncoded()
+//        {
+//        	return new CertificationRequest(reqInfo, sigAlgId, sigBits).GetDerEncoded();
+//        }
+
+		// TODO Figure out how to set parameters on an ISigner
+		private void SetSignatureParameters(
+			ISigner			signature,
+			Asn1Encodable	asn1Params)
+		{
+			if (asn1Params != null && !(asn1Params is Asn1Null))
+			{
+//				AlgorithmParameters sigParams = AlgorithmParameters.GetInstance(signature.getAlgorithm());
+//
+//				try
+//				{
+//					sigParams.init(asn1Params.ToAsn1Object().GetDerEncoded());
+//				}
+//				catch (IOException e)
+//				{
+//					throw new SignatureException("IOException decoding parameters: " + e.Message);
+//				}
+
+				if (signature.AlgorithmName.EndsWith("MGF1"))
+				{
+					throw Platform.CreateNotImplementedException("signature algorithm with MGF1");
+
+//					try
+//					{
+//						signature.setParameter(sigParams.getParameterSpec(PSSParameterSpec.class));
+//					}
+//					catch (GeneralSecurityException e)
+//					{
+//						throw new SignatureException("Exception extracting parameters: " + e.getMessage());
+//					}
+				}
+			}
+		}
+
+		internal static string GetSignatureName(
+			AlgorithmIdentifier sigAlgId)
+		{
+			Asn1Encodable asn1Params = sigAlgId.Parameters;
+
+			if (asn1Params != null && !(asn1Params is Asn1Null))
+			{
+				if (sigAlgId.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+				{
+					RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(asn1Params);
+					return GetDigestAlgName(rsaParams.HashAlgorithm.ObjectID) + "withRSAandMGF1";
+				}
+			}
+
+			return sigAlgId.ObjectID.Id;
+		}
+
+		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/pkcs/Pkcs10CertificationRequestDelaySigned.cs b/Crypto/src/pkcs/Pkcs10CertificationRequestDelaySigned.cs
new file mode 100644
index 000000000..f649b47a2
--- /dev/null
+++ b/Crypto/src/pkcs/Pkcs10CertificationRequestDelaySigned.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Collections;
+using System.Globalization;
+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.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkcs
+{
+	/// <remarks>
+	/// A class for creating and verifying Pkcs10 Certification requests (this is an extension on <see cref="Pkcs10CertificationRequest"/>).
+	/// The requests are made using delay signing. This is useful for situations where
+	/// the private key is in another environment and not directly accessible (e.g. HSM)
+	/// So the first step creates the request, then the signing is done outside this
+	/// object and the signature is then used to complete the request.
+	/// </remarks>
+	/// <code>
+	/// CertificationRequest ::= Sequence {
+	///   certificationRequestInfo  CertificationRequestInfo,
+	///   signatureAlgorithm        AlgorithmIdentifier{{ SignatureAlgorithms }},
+	///   signature                 BIT STRING
+	/// }
+	///
+	/// CertificationRequestInfo ::= Sequence {
+	///   version             Integer { v1(0) } (v1,...),
+	///   subject             Name,
+	///   subjectPKInfo   SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
+	///   attributes          [0] Attributes{{ CRIAttributes }}
+	///  }
+	///
+	///  Attributes { ATTRIBUTE:IOSet } ::= Set OF Attr{{ IOSet }}
+	///
+	///  Attr { ATTRIBUTE:IOSet } ::= Sequence {
+	///    type    ATTRIBUTE.&amp;id({IOSet}),
+	///    values  Set SIZE(1..MAX) OF ATTRIBUTE.&amp;Type({IOSet}{\@type})
+	///  }
+	/// </code>
+	/// see <a href="http://www.rsasecurity.com/rsalabs/node.asp?id=2132"/>
+	public class Pkcs10CertificationRequestDelaySigned : Pkcs10CertificationRequest
+	{
+		protected Pkcs10CertificationRequestDelaySigned()
+			: base()
+		{
+		}
+		public Pkcs10CertificationRequestDelaySigned(
+			byte[] encoded)
+			: base(encoded)
+		{
+		}
+		public Pkcs10CertificationRequestDelaySigned(
+			Asn1Sequence seq)
+			: base(seq)
+		{
+		}
+		public Pkcs10CertificationRequestDelaySigned(
+			Stream input)
+			: base(input)
+		{
+		}
+		public Pkcs10CertificationRequestDelaySigned(
+			string					signatureAlgorithm,
+			X509Name				subject,
+			AsymmetricKeyParameter	publicKey,
+			Asn1Set					attributes,
+			AsymmetricKeyParameter	signingKey)
+			: base(signatureAlgorithm, subject, publicKey, attributes, signingKey)
+		{
+		}
+		/// <summary>
+		/// Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+		/// </summary>
+		/// <param name="signatureAlgorithm">Name of Sig Alg.</param>
+		/// <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param>
+		/// <param name="publicKey">Public Key to be included in cert reqest.</param>
+		/// <param name="attributes">ASN1Set of Attributes.</param>
+		/// <remarks>
+        /// After the object is constructed use the <see cref="GetDataToSign"/> and finally the
+        /// SignRequest methods to finalize the request.
+		/// </remarks>
+		public Pkcs10CertificationRequestDelaySigned(
+			string					signatureAlgorithm,
+			X509Name				subject,
+			AsymmetricKeyParameter	publicKey,
+			Asn1Set					attributes)
+		{
+			if (signatureAlgorithm == null)
+				throw new ArgumentNullException("signatureAlgorithm");
+			if (subject == null)
+				throw new ArgumentNullException("subject");
+			if (publicKey == null)
+				throw new ArgumentNullException("publicKey");
+			if (publicKey.IsPrivate)
+				throw new ArgumentException("expected public key", "publicKey");
+//			DerObjectIdentifier sigOid = SignerUtilities.GetObjectIdentifier(signatureAlgorithm);
+			string algorithmName = signatureAlgorithm.ToUpperInvariant();
+			DerObjectIdentifier sigOid = (DerObjectIdentifier) algorithms[algorithmName];
+			if (sigOid == null)
+			{
+				try
+				{
+					sigOid = new DerObjectIdentifier(algorithmName);
+				}
+				catch (Exception e)
+				{
+					throw new ArgumentException("Unknown signature type requested", e);
+				}
+			}
+			if (noParams.Contains(sigOid))
+			{
+				this.sigAlgId = new AlgorithmIdentifier(sigOid);
+			}
+			else if (exParams.Contains(algorithmName))
+			{
+				this.sigAlgId = new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
+			}
+			else
+			{
+				this.sigAlgId = new AlgorithmIdentifier(sigOid, DerNull.Instance);
+			}
+			SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+			this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes);
+		}
+		public byte[] GetDataToSign()
+		{
+			return reqInfo.GetDerEncoded();
+		}
+		public void SignRequest(byte[] signedData)
+		{
+			//build the signature from the signed data
+			sigBits = new DerBitString(signedData);
+		}
+		public void SignRequest(DerBitString signedData)
+		{
+			//build the signature from the signed data
+			sigBits = signedData;
+		}
+	}
+}
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
new file mode 100644
index 000000000..2e7f2295e
--- /dev/null
+++ b/Crypto/src/pkcs/Pkcs12Store.cs
@@ -0,0 +1,1231 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Encoders;
+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();
+        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
+//		[Obsolete("Use 'Pkcs12StoreBuilder' instead")]
+		public Pkcs12Store()
+			: this(PkcsObjectIdentifiers.PbeWithShaAnd3KeyTripleDesCbc,
+				PkcsObjectIdentifiers.PbewithShaAnd40BitRC2Cbc, false)
+		{
+		}
+
+		// 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();
+
+            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
+				//
+                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()
+		{
+            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;
+					}
+				}
+
+                X509CertificateEntry[] result = new X509CertificateEntry[cs.Count];
+                for (int i = 0; i < cs.Count; ++i)
+                {
+                    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();
+            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; }
+			}
+		}
+	}
+}
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
new file mode 100644
index 000000000..ed566cae9
--- /dev/null
+++ b/Crypto/src/pkcs/PrivateKeyInfoFactory.cs
@@ -0,0 +1,214 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+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;
+
+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);
+		}
+	}
+}
diff --git a/Crypto/src/pkcs/X509CertificateEntry.cs b/Crypto/src/pkcs/X509CertificateEntry.cs
new file mode 100644
index 000000000..2f81dd87b
--- /dev/null
+++ b/Crypto/src/pkcs/X509CertificateEntry.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Pkcs
+{
+    public class X509CertificateEntry
+        : Pkcs12Entry
+    {
+        private readonly X509Certificate cert;
+
+		public X509CertificateEntry(
+            X509Certificate cert)
+			: base(Platform.CreateHashtable())
+        {
+            this.cert = cert;
+        }
+
+#if !(SILVERLIGHT || PORTABLE)
+        [Obsolete]
+        public X509CertificateEntry(
+            X509Certificate	cert,
+            Hashtable		attributes)
+			: base(attributes)
+        {
+            this.cert = cert;
+        }
+#endif
+
+        public X509CertificateEntry(
+            X509Certificate cert,
+            IDictionary     attributes)
+			: base(attributes)
+        {
+            this.cert = cert;
+        }
+
+		public X509Certificate Certificate
+        {
+			get { return this.cert; }
+        }
+
+		public override bool Equals(object obj)
+		{
+			X509CertificateEntry other = obj as X509CertificateEntry;
+
+			if (other == null)
+				return false;
+
+			return cert.Equals(other.cert);
+		}
+
+		public override int GetHashCode()
+		{
+			return ~cert.GetHashCode();
+		}
+	}
+}
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
new file mode 100644
index 000000000..e13e50995
--- /dev/null
+++ b/Crypto/src/pkix/PkixCertPath.cs
@@ -0,0 +1,460 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.OpenSsl;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/**
+	 * An immutable sequence of certificates (a certification path).<br />
+	 * <br />
+	 * This is an abstract class that defines the methods common to all CertPaths.
+	 * Subclasses can handle different kinds of certificates (X.509, PGP, etc.).<br />
+	 * <br />
+	 * All CertPath objects have a type, a list of Certificates, and one or more
+	 * supported encodings. Because the CertPath class is immutable, a CertPath
+	 * cannot change in any externally visible way after being constructed. This
+	 * stipulation applies to all public fields and methods of this class and any
+	 * added or overridden by subclasses.<br />
+	 * <br />
+	 * The type is a string that identifies the type of Certificates in the
+	 * certification path. For each certificate cert in a certification path
+	 * certPath, cert.getType().equals(certPath.getType()) must be true.<br />
+	 * <br />
+	 * The list of Certificates is an ordered List of zero or more Certificates.
+	 * This List and all of the Certificates contained in it must be immutable.<br />
+	 * <br />
+	 * Each CertPath object must support one or more encodings so that the object
+	 * can be translated into a byte array for storage or transmission to other
+	 * parties. Preferably, these encodings should be well-documented standards
+	 * (such as PKCS#7). One of the encodings supported by a CertPath is considered
+	 * the default encoding. This encoding is used if no encoding is explicitly
+	 * requested (for the {@link #getEncoded()} method, for instance).<br />
+	 * <br />
+	 * All CertPath objects are also Serializable. CertPath objects are resolved
+	 * into an alternate {@link CertPathRep} object during serialization. This
+	 * allows a CertPath object to be serialized into an equivalent representation
+	 * regardless of its underlying implementation.<br />
+	 * <br />
+	 * CertPath objects can be created with a CertificateFactory or they can be
+	 * returned by other classes, such as a CertPathBuilder.<br />
+	 * <br />
+	 * By convention, X.509 CertPaths (consisting of X509Certificates), are ordered
+	 * starting with the target certificate and ending with a certificate issued by
+	 * the trust anchor. That is, the issuer of one certificate is the subject of
+	 * the following one. The certificate representing the
+	 * {@link TrustAnchor TrustAnchor} should not be included in the certification
+	 * path. Unvalidated X.509 CertPaths may not follow these conventions. PKIX
+	 * CertPathValidators will detect any departure from these conventions that
+	 * cause the certification path to be invalid and throw a
+	 * CertPathValidatorException.<br />
+	 * <br />
+	 * <strong>Concurrent Access</strong><br />
+	 * <br />
+	 * All CertPath objects must be thread-safe. That is, multiple threads may
+	 * concurrently invoke the methods defined in this class on a single CertPath
+	 * object (or more than one) with no ill effects. This is also true for the List
+	 * returned by CertPath.getCertificates.<br />
+	 * <br />
+	 * Requiring CertPath objects to be immutable and thread-safe allows them to be
+	 * passed around to various pieces of code without worrying about coordinating
+	 * access. Providing this thread-safety is generally not difficult, since the
+	 * CertPath and List objects in question are immutable.
+	 *
+	 * @see CertificateFactory
+	 * @see CertPathBuilder
+	 */
+	/// <summary>
+	/// CertPath implementation for X.509 certificates.
+	/// </summary>
+	public class PkixCertPath
+//		: CertPath
+	{
+		internal static readonly IList certPathEncodings;
+
+        static PkixCertPath()
+        {
+            IList encodings = Platform.CreateArrayList();
+            encodings.Add("PkiPath");
+            encodings.Add("PEM");
+            encodings.Add("PKCS7");
+            certPathEncodings = CollectionUtilities.ReadOnly(encodings);
+        }
+
+        private readonly IList certificates;
+
+		/**
+		 * @param certs
+		 */
+		private static IList SortCerts(
+			IList certs)
+		{
+			if (certs.Count < 2)
+				return certs;
+
+			X509Name issuer = ((X509Certificate)certs[0]).IssuerDN;
+			bool okay = true;
+
+			for (int i = 1; i != certs.Count; i++)
+			{
+				X509Certificate cert = (X509Certificate)certs[i];
+
+				if (issuer.Equivalent(cert.SubjectDN, true))
+				{
+					issuer = ((X509Certificate)certs[i]).IssuerDN;
+				}
+				else
+				{
+					okay = false;
+					break;
+				}
+			}
+
+			if (okay)
+				return certs;
+
+			// find end-entity cert
+            IList retList = Platform.CreateArrayList(certs.Count);
+            IList orig = Platform.CreateArrayList(certs);
+
+			for (int i = 0; i < certs.Count; i++)
+			{
+				X509Certificate cert = (X509Certificate)certs[i];
+				bool           found = false;
+
+				X509Name subject = cert.SubjectDN;
+				foreach (X509Certificate c in certs)
+				{
+					if (c.IssuerDN.Equivalent(subject, true))
+					{
+						found = true;
+						break;
+					}
+				}
+
+				if (!found)
+				{
+					retList.Add(cert);
+					certs.RemoveAt(i);
+				}
+			}
+
+			// can only have one end entity cert - something's wrong, give up.
+			if (retList.Count > 1)
+				return orig;
+
+			for (int i = 0; i != retList.Count; i++)
+			{
+				issuer = ((X509Certificate)retList[i]).IssuerDN;
+
+				for (int j = 0; j < certs.Count; j++)
+				{
+					X509Certificate c = (X509Certificate)certs[j];
+					if (issuer.Equivalent(c.SubjectDN, true))
+					{
+						retList.Add(c);
+						certs.RemoveAt(j);
+						break;
+					}
+				}
+			}
+
+			// make sure all certificates are accounted for.
+			if (certs.Count > 0)
+				return orig;
+
+			return retList;
+		}
+
+		/**
+		 * Creates a CertPath of the specified type.
+		 * This constructor is protected because most users should use
+		 * a CertificateFactory to create CertPaths.
+		 * @param type the standard name of the type of Certificatesin this path
+		 **/
+		public PkixCertPath(
+			ICollection certificates)
+//			: base("X.509")
+		{
+			this.certificates = SortCerts(Platform.CreateArrayList(certificates));
+		}
+
+		public PkixCertPath(
+			Stream inStream)
+			: this(inStream, "PkiPath")
+		{
+		}
+
+		/**
+		 * Creates a CertPath of the specified type.
+		 * This constructor is protected because most users should use
+		 * a CertificateFactory to create CertPaths.
+		 *
+		 * @param type the standard name of the type of Certificatesin this path
+		 **/
+		public PkixCertPath(
+			Stream	inStream,
+			string	encoding)
+//			: base("X.509")
+		{
+            string upper = encoding.ToUpper();
+
+            IList certs;
+			try
+			{
+				if (upper.Equals("PkiPath".ToUpper()))
+				{
+					Asn1InputStream derInStream = new Asn1InputStream(inStream);
+					Asn1Object derObject = derInStream.ReadObject();
+					if (!(derObject is Asn1Sequence))
+					{
+						throw new CertificateException(
+							"input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
+					}
+
+                    certs = Platform.CreateArrayList();
+
+                    foreach (Asn1Encodable ae in (Asn1Sequence)derObject)
+                    {
+                        byte[] derBytes = ae.GetEncoded(Asn1Encodable.Der);
+                        Stream certInStream = new MemoryStream(derBytes, false);
+
+                        // TODO Is inserting at the front important (list will be sorted later anyway)?
+                        certs.Insert(0, new X509CertificateParser().ReadCertificate(certInStream));
+					}
+				}
+                else if (upper.Equals("PKCS7") || upper.Equals("PEM"))
+				{
+                    certs = Platform.CreateArrayList(new X509CertificateParser().ReadCertificates(inStream));
+				}
+				else
+				{
+					throw new CertificateException("unsupported encoding: " + encoding);
+				}
+			}
+			catch (IOException ex)
+			{
+				throw new CertificateException(
+					"IOException throw while decoding CertPath:\n"
+					+ ex.ToString());
+			}
+
+			this.certificates = SortCerts(certs);
+		}
+
+		/**
+		 * Returns an iteration of the encodings supported by this
+		 * certification path, with the default encoding
+		 * first. Attempts to modify the returned Iterator via its
+		 * remove method result in an UnsupportedOperationException.
+		 *
+		 * @return an Iterator over the names of the supported encodings (as Strings)
+		 **/
+		public virtual IEnumerable Encodings
+		{
+            get { return new EnumerableProxy(certPathEncodings); }
+		}
+
+		/**
+		* Compares this certification path for equality with the specified object.
+		* Two CertPaths are equal if and only if their types are equal and their
+		* certificate Lists (and by implication the Certificates in those Lists)
+		* are equal. A CertPath is never equal to an object that is not a CertPath.<br />
+		* <br />
+		* This algorithm is implemented by this method. If it is overridden, the
+		* behavior specified here must be maintained.
+		*
+		* @param other
+		*            the object to test for equality with this certification path
+		*
+		* @return true if the specified object is equal to this certification path,
+		*         false otherwise
+		*
+		* @see Object#hashCode() Object.hashCode()
+		*/
+		public override bool Equals(
+			object obj)
+		{
+			if (this == obj)
+				return true;
+
+			PkixCertPath other = obj as PkixCertPath;
+			if (other == null)
+				return false;
+
+//			if (!this.Type.Equals(other.Type))
+//				return false;
+
+			//return this.Certificates.Equals(other.Certificates);
+
+			// TODO Extract this to a utility class
+			IList thisCerts = this.Certificates;
+			IList otherCerts = other.Certificates;
+
+			if (thisCerts.Count != otherCerts.Count)
+				return false;
+
+			IEnumerator e1 = thisCerts.GetEnumerator();
+			IEnumerator e2 = thisCerts.GetEnumerator();
+
+			while (e1.MoveNext())
+			{
+				e2.MoveNext();
+
+				if (!Platform.Equals(e1.Current, e2.Current))
+					return false;
+			}
+
+			return true;
+		}
+
+		public override int GetHashCode()
+		{
+			// FIXME?
+			return this.Certificates.GetHashCode();
+		}
+
+		/**
+		 * Returns the encoded form of this certification path, using
+		 * the default encoding.
+		 *
+		 * @return the encoded bytes
+		 * @exception CertificateEncodingException if an encoding error occurs
+		 **/
+		public virtual byte[] GetEncoded()
+		{
+			foreach (object enc in Encodings)
+			{
+				if (enc is string)
+				{
+					return GetEncoded((string)enc);
+				}
+			}
+			return null;
+		}
+
+		/**
+		 * Returns the encoded form of this certification path, using
+		 * the specified encoding.
+		 *
+		 * @param encoding the name of the encoding to use
+		 * @return the encoded bytes
+		 * @exception CertificateEncodingException if an encoding error
+		 * occurs or the encoding requested is not supported
+		 *
+		 */
+		public virtual byte[] GetEncoded(
+			string encoding)
+		{
+			if (Platform.CompareIgnoreCase(encoding, "PkiPath") == 0)
+			{
+				Asn1EncodableVector v = new Asn1EncodableVector();
+
+				for (int i = certificates.Count - 1; i >= 0; i--)
+				{
+					v.Add(ToAsn1Object((X509Certificate) certificates[i]));
+				}
+
+				return ToDerEncoded(new DerSequence(v));
+			}
+            else if (Platform.CompareIgnoreCase(encoding, "PKCS7") == 0)
+			{
+				Asn1.Pkcs.ContentInfo encInfo = new Asn1.Pkcs.ContentInfo(
+					PkcsObjectIdentifiers.Data, null);
+
+				Asn1EncodableVector v = new Asn1EncodableVector();
+				for (int i = 0; i != certificates.Count; i++)
+				{
+					v.Add(ToAsn1Object((X509Certificate)certificates[i]));
+				}
+
+				Asn1.Pkcs.SignedData sd = new Asn1.Pkcs.SignedData(
+					new DerInteger(1),
+					new DerSet(),
+					encInfo,
+					new DerSet(v),
+					null,
+					new DerSet());
+
+				return ToDerEncoded(new Asn1.Pkcs.ContentInfo(PkcsObjectIdentifiers.SignedData, sd));
+			}
+            else if (Platform.CompareIgnoreCase(encoding, "PEM") == 0)
+			{
+				MemoryStream bOut = new MemoryStream();
+				PemWriter pWrt = new PemWriter(new StreamWriter(bOut));
+
+				try
+				{
+					for (int i = 0; i != certificates.Count; i++)
+					{
+						pWrt.WriteObject(certificates[i]);
+					}
+
+                    pWrt.Writer.Dispose();
+				}
+				catch (Exception)
+				{
+					throw new CertificateEncodingException("can't encode certificate for PEM encoded path");
+				}
+
+				return bOut.ToArray();
+			}
+			else
+			{
+				throw new CertificateEncodingException("unsupported encoding: " + encoding);
+			}
+		}
+
+		/// <summary>
+		/// Returns the list of certificates in this certification
+		/// path.
+		/// </summary>
+		public virtual IList Certificates
+		{
+            get { return CollectionUtilities.ReadOnly(certificates); }
+		}
+
+		/**
+		 * Return a DERObject containing the encoded certificate.
+		 *
+		 * @param cert the X509Certificate object to be encoded
+		 *
+		 * @return the DERObject
+		 **/
+		private Asn1Object ToAsn1Object(
+			X509Certificate cert)
+		{
+			try
+			{
+				return Asn1Object.FromByteArray(cert.GetEncoded());
+			}
+			catch (Exception e)
+			{
+				throw new CertificateEncodingException("Exception while encoding certificate", e);
+			}
+		}
+
+		private byte[] ToDerEncoded(Asn1Encodable obj)
+		{
+			try
+			{
+				return obj.GetEncoded(Asn1Encodable.Der);
+			}
+			catch (IOException e)
+			{
+				throw new CertificateEncodingException("Exception thrown", e);
+			}
+		}
+	}
+}
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
new file mode 100644
index 000000000..106075a63
--- /dev/null
+++ b/Crypto/src/pkix/PkixCertPathBuilderException.cs
@@ -0,0 +1,19 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/// <summary>
+	/// Summary description for PkixCertPathBuilderException.
+	/// </summary>
+	public class PkixCertPathBuilderException : GeneralSecurityException
+	{
+		public PkixCertPathBuilderException() : base() { }
+		
+		public PkixCertPathBuilderException(string message) : base(message)	{ }  
+
+		public PkixCertPathBuilderException(string message, Exception exception) : base(message, exception) { }
+		
+	}
+}
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
new file mode 100644
index 000000000..504a3c646
--- /dev/null
+++ b/Crypto/src/pkix/PkixCertPathValidatorException.cs
@@ -0,0 +1,218 @@
+using System;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/**
+	 * An exception indicating one of a variety of problems encountered when 
+	 * validating a certification path. <br />
+	 * <br />
+	 * A <code>CertPathValidatorException</code> provides support for wrapping
+	 * exceptions. The {@link #getCause getCause} method returns the throwable, 
+	 * if any, that caused this exception to be thrown. <br />
+	 * <br />
+	 * A <code>CertPathValidatorException</code> may also include the 
+	 * certification path that was being validated when the exception was thrown 
+	 * and the index of the certificate in the certification path that caused the 
+	 * exception to be thrown. Use the {@link #getCertPath getCertPath} and
+	 * {@link #getIndex getIndex} methods to retrieve this information.<br />
+	 * <br />
+	 * <b>Concurrent Access</b><br />
+	 * <br />
+	 * Unless otherwise specified, the methods defined in this class are not
+	 * thread-safe. Multiple threads that need to access a single
+	 * object concurrently should synchronize amongst themselves and
+	 * provide the necessary locking. Multiple threads each manipulating
+	 * separate objects need not synchronize.
+	 *
+	 * @see CertPathValidator
+	 **/
+
+	public class PkixCertPathValidatorException : GeneralSecurityException
+	{
+		private Exception cause;
+		private PkixCertPath certPath;
+		private int index = -1;
+
+		public PkixCertPathValidatorException() : base() { }
+
+		/// <summary>
+		/// Creates a <code>PkixCertPathValidatorException</code> with the given detail
+		/// message. A detail message is a <code>String</code> that describes this
+		/// particular exception. 
+		/// </summary>
+		/// <param name="message">the detail message</param>
+		public PkixCertPathValidatorException(string message) : base(message) { }
+
+		/// <summary>
+		/// Creates a <code>PkixCertPathValidatorException</code> with the specified
+		/// detail message and cause.
+		/// </summary>
+		/// <param name="message">the detail message</param>
+		/// <param name="cause">the cause (which is saved for later retrieval by the
+		/// {@link #getCause getCause()} method). (A <code>null</code>
+		/// value is permitted, and indicates that the cause is
+		/// nonexistent or unknown.)</param>
+		public PkixCertPathValidatorException(string message, Exception cause) : base(message)
+		{
+			this.cause = cause;
+		}
+
+		/// <summary>
+		/// Creates a <code>PkixCertPathValidatorException</code> with the specified
+		/// detail message, cause, certification path, and index.
+		/// </summary>
+		/// <param name="message">the detail message (or <code>null</code> if none)</param>
+		/// <param name="cause">the cause (or <code>null</code> if none)</param>
+		/// <param name="certPath">the certification path that was in the process of being
+		/// validated when the error was encountered</param>
+		/// <param name="index">the index of the certificate in the certification path that</param>																																																																																   * 
+		public PkixCertPathValidatorException(
+			string			message,
+			Exception		cause,
+			PkixCertPath	certPath,
+			int				index)
+			: base(message)
+		{
+			if (certPath == null && index != -1)
+			{
+				throw new ArgumentNullException(
+					"certPath = null and index != -1");
+			}
+			if (index < -1
+				|| (certPath != null && index >= certPath.Certificates.Count))
+			{
+				throw new IndexOutOfRangeException(
+					" index < -1 or out of bound of certPath.getCertificates()");
+			}
+
+			this.cause = cause;
+			this.certPath = certPath;
+			this.index = index;
+		}
+
+		//
+		// Prints a stack trace to a <code>PrintWriter</code>, including the
+		// backtrace of the cause, if any.
+		// 
+		// @param pw
+		//            the <code>PrintWriter</code> to use for output
+		//
+		//		public void printStackTrace(PrintWriter pw)
+		//		{
+		//			super.printStackTrace(pw);
+		//			if (getCause() != null)
+		//			{
+		//				getCause().printStackTrace(pw);
+		//			}
+		//	}
+		//}
+
+
+		//	/**
+		//	 * Creates a <code>CertPathValidatorException</code> that wraps the
+		//	 * specified throwable. This allows any exception to be converted into a
+		//	 * <code>CertPathValidatorException</code>, while retaining information
+		//	 * about the wrapped exception, which may be useful for debugging. The
+		//	 * detail message is set to (<code>cause==null ? null : cause.toString()
+		//	 * </code>)
+		//	 * (which typically contains the class and detail message of cause).
+		//	 * 
+		//	 * @param cause
+		//	 *            the cause (which is saved for later retrieval by the
+		//	 *            {@link #getCause getCause()} method). (A <code>null</code>
+		//	 *            value is permitted, and indicates that the cause is
+		//	 *            nonexistent or unknown.)
+		//	 */
+		//	public PkixCertPathValidatorException(Throwable cause)
+		//	{
+		//		this.cause = cause;
+		//	}
+		//
+
+		/// <summary>
+		/// Returns the detail message for this <code>CertPathValidatorException</code>.
+		/// </summary>
+		/// <returns>the detail message, or <code>null</code> if neither the message nor cause were specified</returns>
+		public override string Message
+		{
+			get
+			{
+				string message = base.Message;
+
+				if (message != null)
+				{
+					return message;
+				}
+
+				if (cause != null)
+				{
+					return cause.Message;
+				}
+
+				return null;
+			}
+		}
+
+	/**
+	 * Returns the certification path that was being validated when the
+	 * exception was thrown.
+	 * 
+	 * @return the <code>CertPath</code> that was being validated when the
+	 *         exception was thrown (or <code>null</code> if not specified)
+	 */
+		public PkixCertPath CertPath
+		{
+			get { return certPath; }
+		}
+
+	/**
+	 * Returns the index of the certificate in the certification path that
+	 * caused the exception to be thrown. Note that the list of certificates in
+	 * a <code>CertPath</code> is zero based. If no index has been set, -1 is
+	 * returned.
+	 * 
+	 * @return the index that has been set, or -1 if none has been set
+	 */
+	public int Index
+	{
+        get { return index; }
+	}
+
+//	/**
+//	 * Returns the cause of this <code>CertPathValidatorException</code> or
+//	 * <code>null</code> if the cause is nonexistent or unknown.
+//	 * 
+//	 * @return the cause of this throwable or <code>null</code> if the cause
+//	 *         is nonexistent or unknown.
+//	 */
+//	public Throwable getCause()
+//	{
+//		return cause;
+//	}
+//
+//	/**
+//	 * Returns a string describing this exception, including a description of
+//	 * the internal (wrapped) cause if there is one.
+//	 * 
+//	 * @return a string representation of this
+//	 *         <code>CertPathValidatorException</code>
+//	 */
+//	public String toString()
+//	{
+//		StringBuffer sb = new StringBuffer();
+//		String s = getMessage();
+//		if (s != null)
+//		{
+//			sb.append(s);
+//		}
+//		if (getIndex() >= 0)
+//		{
+//			sb.append("index in certpath: ").append(getIndex()).append('\n');
+//			sb.append(getCertPath());
+//		}
+//		return sb.toString();
+//	}
+
+	}
+}
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
new file mode 100644
index 000000000..305b2de35
--- /dev/null
+++ b/Crypto/src/pkix/PkixCertPathValidatorUtilities.cs
@@ -0,0 +1,1194 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.IsisMtt;
+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.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Extension;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+	/// <summary>
+	/// Summary description for PkixCertPathValidatorUtilities.
+	/// </summary>
+	public class PkixCertPathValidatorUtilities
+	{
+		private static readonly PkixCrlUtilities CrlUtilities = new PkixCrlUtilities();
+
+		internal static readonly string ANY_POLICY = "2.5.29.32.0";
+
+		internal static readonly string CRL_NUMBER = X509Extensions.CrlNumber.Id;
+
+		/// <summary>
+		/// key usage bits
+		/// </summary>
+		internal static readonly int KEY_CERT_SIGN = 5;
+		internal static readonly int CRL_SIGN = 6;
+
+		internal static readonly string[] crlReasons = new string[]
+		{
+			"unspecified",
+			"keyCompromise",
+			"cACompromise",
+			"affiliationChanged",
+			"superseded",
+			"cessationOfOperation",
+			"certificateHold",
+			"unknown",
+			"removeFromCRL",
+			"privilegeWithdrawn",
+			"aACompromise"
+		};
+
+		/// <summary>
+		/// Search the given Set of TrustAnchor's for one that is the
+		/// issuer of the given X509 certificate.
+		/// </summary>
+		/// <param name="cert">the X509 certificate</param>
+		/// <param name="trustAnchors">a Set of TrustAnchor's</param>
+		/// <returns>the <code>TrustAnchor</code> object if found or
+		/// <code>null</code> if not.
+		/// </returns>
+		/// @exception
+		internal static TrustAnchor FindTrustAnchor(
+			X509Certificate	cert,
+			ISet			trustAnchors)
+		{
+			IEnumerator iter = trustAnchors.GetEnumerator();
+			TrustAnchor trust = null;
+			AsymmetricKeyParameter trustPublicKey = null;
+			Exception invalidKeyEx = null;
+
+			X509CertStoreSelector certSelectX509 = new X509CertStoreSelector();
+
+			try
+			{
+				certSelectX509.Subject = GetIssuerPrincipal(cert);
+			}
+			catch (IOException ex)
+			{
+				throw new Exception("Cannot set subject search criteria for trust anchor.", ex);
+			}
+
+			while (iter.MoveNext() && trust == null)
+			{
+				trust = (TrustAnchor) iter.Current;
+				if (trust.TrustedCert != null)
+				{
+					if (certSelectX509.Match(trust.TrustedCert))
+					{
+						trustPublicKey = trust.TrustedCert.GetPublicKey();
+					}
+					else
+					{
+						trust = null;
+					}
+				}
+				else if (trust.CAName != null && trust.CAPublicKey != null)
+				{
+					try
+					{
+						X509Name certIssuer = GetIssuerPrincipal(cert);
+						X509Name caName = new X509Name(trust.CAName);
+
+						if (certIssuer.Equivalent(caName, true))
+						{
+							trustPublicKey = trust.CAPublicKey;
+						}
+						else
+						{
+							trust = null;
+						}
+					}
+					catch (InvalidParameterException)
+					{
+						trust = null;
+					}
+				}
+				else
+				{
+					trust = null;
+				}
+
+				if (trustPublicKey != null)
+				{
+					try
+					{
+						cert.Verify(trustPublicKey);
+					}
+					catch (Exception ex)
+					{
+						invalidKeyEx = ex;
+						trust = null;
+					}
+				}
+			}
+
+			if (trust == null && invalidKeyEx != null)
+			{
+				throw new Exception("TrustAnchor found but certificate validation failed.", invalidKeyEx);
+			}
+
+			return trust;
+		}
+
+		internal static void AddAdditionalStoresFromAltNames(
+			X509Certificate	cert,
+			PkixParameters	pkixParams)
+		{
+			// if in the IssuerAltName extension an URI
+			// is given, add an additinal X.509 store
+			if (cert.GetIssuerAlternativeNames() != null)
+			{
+				IEnumerator it = cert.GetIssuerAlternativeNames().GetEnumerator();
+				while (it.MoveNext())
+				{
+					// look for URI
+					IList list = (IList)it.Current;
+					//if (list[0].Equals(new Integer(GeneralName.UniformResourceIdentifier)))
+					if (list[0].Equals(GeneralName.UniformResourceIdentifier))
+					{
+						// found
+						string temp = (string)list[1];
+						PkixCertPathValidatorUtilities.AddAdditionalStoreFromLocation(temp, pkixParams);
+					}
+				}
+			}
+		}
+
+		internal static DateTime GetValidDate(PkixParameters paramsPKIX)
+		{
+			DateTimeObject validDate = paramsPKIX.Date;
+
+			if (validDate == null)
+				return DateTime.UtcNow;
+
+			return validDate.Value;
+		}
+
+		/// <summary>
+		/// Returns the issuer of an attribute certificate or certificate.
+		/// </summary>
+		/// <param name="cert">The attribute certificate or certificate.</param>
+		/// <returns>The issuer as <code>X500Principal</code>.</returns>
+		internal static X509Name GetIssuerPrincipal(
+			object cert)
+		{
+			if (cert is X509Certificate)
+			{
+				return ((X509Certificate)cert).IssuerDN;
+			}
+			else
+			{
+				return ((IX509AttributeCertificate)cert).Issuer.GetPrincipals()[0];
+			}
+		}
+
+		internal static bool IsSelfIssued(
+			X509Certificate cert)
+		{
+			return cert.SubjectDN.Equivalent(cert.IssuerDN, true);
+		}
+
+		internal static AlgorithmIdentifier GetAlgorithmIdentifier(
+			AsymmetricKeyParameter key)
+		{
+			try
+			{
+				SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(key);
+
+				return info.AlgorithmID;
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathValidatorException("Subject public key cannot be decoded.", e);
+			}
+		}
+
+		internal static bool IsAnyPolicy(
+			ISet policySet)
+		{
+			return policySet == null || policySet.Contains(ANY_POLICY) || policySet.Count == 0;
+		}
+
+		internal static void AddAdditionalStoreFromLocation(
+			string			location,
+			PkixParameters	pkixParams)
+		{
+			if (pkixParams.IsAdditionalLocationsEnabled)
+			{
+				try
+				{
+					if (location.StartsWith("ldap://"))
+					{
+						// ldap://directory.d-trust.net/CN=D-TRUST
+						// Qualified CA 2003 1:PN,O=D-Trust GmbH,C=DE
+						// skip "ldap://"
+						location = location.Substring(7);
+						// after first / baseDN starts
+						string url;//, baseDN;
+						int slashPos = location.IndexOf('/');
+						if (slashPos != -1)
+						{
+							url = "ldap://" + location.Substring(0, slashPos);
+//							baseDN = location.Substring(slashPos);
+						}
+						else
+						{
+							url = "ldap://" + location;
+//							baseDN = nsull;
+						}
+
+						throw Platform.CreateNotImplementedException("LDAP cert/CRL stores");
+
+						// use all purpose parameters
+						//X509LDAPCertStoreParameters ldapParams = new X509LDAPCertStoreParameters.Builder(
+						//                                url, baseDN).build();
+						//pkixParams.AddAdditionalStore(X509Store.getInstance(
+						//    "CERTIFICATE/LDAP", ldapParams));
+						//pkixParams.AddAdditionalStore(X509Store.getInstance(
+						//    "CRL/LDAP", ldapParams));
+						//pkixParams.AddAdditionalStore(X509Store.getInstance(
+						//    "ATTRIBUTECERTIFICATE/LDAP", ldapParams));
+						//pkixParams.AddAdditionalStore(X509Store.getInstance(
+						//    "CERTIFICATEPAIR/LDAP", ldapParams));
+					}
+				}
+				catch (Exception)
+				{
+					// cannot happen
+					throw new Exception("Exception adding X.509 stores.");
+				}
+			}
+		}
+
+		private static BigInteger GetSerialNumber(
+			object cert)
+		{
+			if (cert is X509Certificate)
+			{
+				return ((X509Certificate)cert).SerialNumber;
+			}
+			else
+			{
+				return ((X509V2AttributeCertificate)cert).SerialNumber;
+			}
+		}
+
+		//
+		// policy checking
+		//
+
+		internal static ISet GetQualifierSet(Asn1Sequence qualifiers)
+		{
+			ISet pq = new HashSet();
+
+			if (qualifiers == null)
+			{
+				return pq;
+			}
+
+			foreach (Asn1Encodable ae in qualifiers)
+			{
+				try
+				{
+//					pq.Add(PolicyQualifierInfo.GetInstance(Asn1Object.FromByteArray(ae.GetEncoded())));
+					pq.Add(PolicyQualifierInfo.GetInstance(ae.ToAsn1Object()));
+				}
+				catch (IOException ex)
+				{
+					throw new PkixCertPathValidatorException("Policy qualifier info cannot be decoded.", ex);
+				}
+			}
+
+			return pq;
+		}
+
+		internal static PkixPolicyNode RemovePolicyNode(
+			PkixPolicyNode validPolicyTree,
+			IList[] policyNodes,
+			PkixPolicyNode _node)
+		{
+			PkixPolicyNode _parent = (PkixPolicyNode)_node.Parent;
+
+			if (validPolicyTree == null)
+			{
+				return null;
+			}
+
+			if (_parent == null)
+			{
+				for (int j = 0; j < policyNodes.Length; j++)
+				{
+                    policyNodes[j] = Platform.CreateArrayList();
+				}
+
+				return null;
+			}
+			else
+			{
+				_parent.RemoveChild(_node);
+				RemovePolicyNodeRecurse(policyNodes, _node);
+
+				return validPolicyTree;
+			}
+		}
+
+		private static void RemovePolicyNodeRecurse(IList[] policyNodes, PkixPolicyNode _node)
+		{
+			policyNodes[_node.Depth].Remove(_node);
+
+			if (_node.HasChildren)
+			{
+				foreach (PkixPolicyNode _child in _node.Children)
+				{
+					RemovePolicyNodeRecurse(policyNodes, _child);
+				}
+			}
+		}
+
+		internal static void PrepareNextCertB1(
+			int i,
+			IList[] policyNodes,
+			string id_p,
+			IDictionary m_idp,
+			X509Certificate cert)
+		{
+			bool idp_found = false;
+			IEnumerator nodes_i = policyNodes[i].GetEnumerator();
+			while (nodes_i.MoveNext())
+			{
+				PkixPolicyNode node = (PkixPolicyNode)nodes_i.Current;
+				if (node.ValidPolicy.Equals(id_p))
+				{
+					idp_found = true;
+					node.ExpectedPolicies = (ISet)m_idp[id_p];
+					break;
+				}
+			}
+
+			if (!idp_found)
+			{
+				nodes_i = policyNodes[i].GetEnumerator();
+				while (nodes_i.MoveNext())
+				{
+					PkixPolicyNode node = (PkixPolicyNode)nodes_i.Current;
+					if (ANY_POLICY.Equals(node.ValidPolicy))
+					{
+						ISet pq = null;
+						Asn1Sequence policies = null;
+						try
+						{
+							policies = DerSequence.GetInstance(GetExtensionValue(cert, X509Extensions.CertificatePolicies));
+						}
+						catch (Exception e)
+						{
+							throw new Exception("Certificate policies cannot be decoded.", e);
+						}
+
+						IEnumerator enm = policies.GetEnumerator();
+						while (enm.MoveNext())
+						{
+							PolicyInformation pinfo = null;
+
+							try
+							{
+								pinfo = PolicyInformation.GetInstance(enm.Current);
+							}
+							catch (Exception ex)
+							{
+								throw new Exception("Policy information cannot be decoded.", ex);
+							}
+
+							if (ANY_POLICY.Equals(pinfo.PolicyIdentifier.Id))
+							{
+								try
+								{
+									pq = GetQualifierSet(pinfo.PolicyQualifiers);
+								}
+								catch (PkixCertPathValidatorException ex)
+								{
+									throw new PkixCertPathValidatorException(
+										"Policy qualifier info set could not be built.", ex);
+								}
+								break;
+							}
+						}
+						bool ci = false;
+						ISet critExtOids = cert.GetCriticalExtensionOids();
+						if (critExtOids != null)
+						{
+							ci = critExtOids.Contains(X509Extensions.CertificatePolicies.Id);
+						}
+
+						PkixPolicyNode p_node = (PkixPolicyNode)node.Parent;
+						if (ANY_POLICY.Equals(p_node.ValidPolicy))
+						{
+							PkixPolicyNode c_node = new PkixPolicyNode(
+                                Platform.CreateArrayList(), i,
+								(ISet)m_idp[id_p],
+								p_node, pq, id_p, ci);
+							p_node.AddChild(c_node);
+							policyNodes[i].Add(c_node);
+						}
+						break;
+					}
+				}
+			}
+		}
+
+		internal static PkixPolicyNode PrepareNextCertB2(
+			int				i,
+			IList[]			policyNodes,
+			string			id_p,
+			PkixPolicyNode	validPolicyTree)
+		{
+			int pos = 0;
+
+			// Copy to avoid RemoveAt calls interfering with enumeration
+            foreach (PkixPolicyNode node in Platform.CreateArrayList(policyNodes[i]))
+			{
+				if (node.ValidPolicy.Equals(id_p))
+				{
+					PkixPolicyNode p_node = (PkixPolicyNode)node.Parent;
+					p_node.RemoveChild(node);
+
+					// Removal of element at current iterator position not supported in C#
+					//nodes_i.remove();
+					policyNodes[i].RemoveAt(pos);
+
+					for (int k = (i - 1); k >= 0; k--)
+					{
+						IList nodes = policyNodes[k];
+						for (int l = 0; l < nodes.Count; l++)
+						{
+							PkixPolicyNode node2 = (PkixPolicyNode)nodes[l];
+							if (!node2.HasChildren)
+							{
+								validPolicyTree = RemovePolicyNode(validPolicyTree, policyNodes, node2);
+								if (validPolicyTree == null)
+									break;
+							}
+						}
+					}
+				}
+				else
+				{
+					++pos;
+				}
+			}
+			return validPolicyTree;
+		}
+
+		internal static void GetCertStatus(
+			DateTime validDate,
+			X509Crl crl,
+			Object cert,
+			CertStatus certStatus)
+		{
+			X509Crl bcCRL = null;
+
+			try
+			{
+				bcCRL = new X509Crl(CertificateList.GetInstance((Asn1Sequence)Asn1Sequence.FromByteArray(crl.GetEncoded())));
+			}
+			catch (Exception exception)
+			{
+				throw new Exception("Bouncy Castle X509Crl could not be created.", exception);
+			}
+
+			X509CrlEntry crl_entry = (X509CrlEntry)bcCRL.GetRevokedCertificate(GetSerialNumber(cert));
+
+			if (crl_entry == null)
+				return;
+
+			X509Name issuer = GetIssuerPrincipal(cert);
+
+			if (issuer.Equivalent(crl_entry.GetCertificateIssuer(), true)
+				|| issuer.Equivalent(crl.IssuerDN, true))
+			{
+				DerEnumerated reasonCode = null;
+				if (crl_entry.HasExtensions)
+				{
+					try
+					{
+						reasonCode = DerEnumerated.GetInstance(
+							GetExtensionValue(crl_entry, X509Extensions.ReasonCode));
+					}
+					catch (Exception e)
+					{
+						new Exception(
+							"Reason code CRL entry extension could not be decoded.",
+							e);
+					}
+				}
+
+				// for reason keyCompromise, caCompromise, aACompromise or
+				// unspecified
+				if (!(validDate.Ticks < crl_entry.RevocationDate.Ticks)
+					|| reasonCode == null
+					|| reasonCode.Value.TestBit(0)
+					|| reasonCode.Value.TestBit(1)
+					|| reasonCode.Value.TestBit(2)
+					|| reasonCode.Value.TestBit(8))
+				{
+					if (reasonCode != null) // (i) or (j) (1)
+					{
+						certStatus.Status = reasonCode.Value.SignValue;
+					}
+					else // (i) or (j) (2)
+					{
+						certStatus.Status = CrlReason.Unspecified;
+					}
+					certStatus.RevocationDate = new DateTimeObject(crl_entry.RevocationDate);
+				}
+			}
+		}
+
+		/**
+		* Return the next working key inheriting DSA parameters if necessary.
+		* <p>
+		* This methods inherits DSA parameters from the indexed certificate or
+		* previous certificates in the certificate chain to the returned
+		* <code>PublicKey</code>. The list is searched upwards, meaning the end
+		* certificate is at position 0 and previous certificates are following.
+		* </p>
+		* <p>
+		* If the indexed certificate does not contain a DSA key this method simply
+		* returns the public key. If the DSA key already contains DSA parameters
+		* the key is also only returned.
+		* </p>
+		*
+		* @param certs The certification path.
+		* @param index The index of the certificate which contains the public key
+		*            which should be extended with DSA parameters.
+		* @return The public key of the certificate in list position
+		*         <code>index</code> extended with DSA parameters if applicable.
+		* @throws Exception if DSA parameters cannot be inherited.
+		*/
+		internal static AsymmetricKeyParameter GetNextWorkingKey(
+			IList	certs,
+			int		index)
+		{
+			//Only X509Certificate
+			X509Certificate cert = (X509Certificate)certs[index];
+
+			AsymmetricKeyParameter pubKey = cert.GetPublicKey();
+
+			if (!(pubKey is DsaPublicKeyParameters))
+				return pubKey;
+
+			DsaPublicKeyParameters dsaPubKey = (DsaPublicKeyParameters)pubKey;
+
+			if (dsaPubKey.Parameters != null)
+				return dsaPubKey;
+
+			for (int i = index + 1; i < certs.Count; i++)
+			{
+				X509Certificate parentCert = (X509Certificate)certs[i];
+				pubKey = parentCert.GetPublicKey();
+
+				if (!(pubKey is DsaPublicKeyParameters))
+				{
+					throw new PkixCertPathValidatorException(
+						"DSA parameters cannot be inherited from previous certificate.");
+				}
+
+				DsaPublicKeyParameters prevDSAPubKey = (DsaPublicKeyParameters)pubKey;
+
+				if (prevDSAPubKey.Parameters == null)
+					continue;
+
+				DsaParameters dsaParams = prevDSAPubKey.Parameters;
+
+				try
+				{
+					return new DsaPublicKeyParameters(dsaPubKey.Y, dsaParams);
+				}
+				catch (Exception exception)
+				{
+					throw new Exception(exception.Message);
+				}
+			}
+
+			throw new PkixCertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
+		}
+
+		internal static DateTime GetValidCertDateFromValidityModel(
+			PkixParameters	paramsPkix,
+			PkixCertPath	certPath,
+			int				index)
+		{
+			if (paramsPkix.ValidityModel != PkixParameters.ChainValidityModel)
+			{
+				return GetValidDate(paramsPkix);
+			}
+
+			// if end cert use given signing/encryption/... time
+			if (index <= 0)
+			{
+				return PkixCertPathValidatorUtilities.GetValidDate(paramsPkix);
+				// else use time when previous cert was created
+			}
+
+			if (index - 1 == 0)
+			{
+				DerGeneralizedTime dateOfCertgen = null;
+				try
+				{
+					X509Certificate cert = (X509Certificate)certPath.Certificates[index - 1];
+					Asn1OctetString extVal = cert.GetExtensionValue(
+						IsisMttObjectIdentifiers.IdIsisMttATDateOfCertGen);
+					dateOfCertgen = DerGeneralizedTime.GetInstance(extVal);
+				}
+				catch (ArgumentException)
+				{
+					throw new Exception(
+						"Date of cert gen extension could not be read.");
+				}
+				if (dateOfCertgen != null)
+				{
+					try
+					{
+						return dateOfCertgen.ToDateTime();
+					}
+					catch (ArgumentException e)
+					{
+						throw new Exception(
+							"Date from date of cert gen extension could not be parsed.",
+							e);
+					}
+				}
+			}
+
+			return ((X509Certificate)certPath.Certificates[index - 1]).NotBefore;
+		}
+
+		/// <summary>
+		/// Return a Collection of all certificates or attribute certificates found
+		/// in the X509Store's that are matching the certSelect criteriums.
+		/// </summary>
+		/// <param name="certSelect">a {@link Selector} object that will be used to select
+		/// 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.
+		/// May be empty but never <code>null</code>.</returns>
+		/// <exception cref="Exception"></exception>
+		internal static ICollection FindCertificates(
+			X509CertStoreSelector	certSelect,
+			IList					certStores)
+		{
+			ISet certs = new HashSet();
+
+			foreach (IX509Store certStore in certStores)
+			{
+				try
+				{
+//					certs.AddAll(certStore.GetMatches(certSelect));
+					foreach (X509Certificate c in certStore.GetMatches(certSelect))
+					{
+						certs.Add(c);
+					}
+				}
+				catch (Exception e)
+				{
+					throw new Exception("Problem while picking certificates from X.509 store.", e);
+				}
+			}
+
+			return certs;
+		}
+
+		/**
+		* Add the CRL issuers from the cRLIssuer field of the distribution point or
+		* from the certificate if not given to the issuer criterion of the
+		* <code>selector</code>.
+		* <p>
+		* The <code>issuerPrincipals</code> are a collection with a single
+		* <code>X500Principal</code> for <code>X509Certificate</code>s. For
+		* {@link X509AttributeCertificate}s the issuer may contain more than one
+		* <code>X500Principal</code>.
+		* </p>
+		*
+		* @param dp The distribution point.
+		* @param issuerPrincipals The issuers of the certificate or attribute
+		*            certificate which contains the distribution point.
+		* @param selector The CRL selector.
+		* @param pkixParams The PKIX parameters containing the cert stores.
+		* @throws Exception if an exception occurs while processing.
+		* @throws ClassCastException if <code>issuerPrincipals</code> does not
+		* contain only <code>X500Principal</code>s.
+		*/
+		internal static void GetCrlIssuersFromDistributionPoint(
+			DistributionPoint		dp,
+			ICollection				issuerPrincipals,
+			X509CrlStoreSelector	selector,
+			PkixParameters			pkixParams)
+		{
+            IList issuers = Platform.CreateArrayList();
+			// indirect CRL
+			if (dp.CrlIssuer != null)
+			{
+				GeneralName[] genNames = dp.CrlIssuer.GetNames();
+				// look for a DN
+				for (int j = 0; j < genNames.Length; j++)
+				{
+					if (genNames[j].TagNo == GeneralName.DirectoryName)
+					{
+						try
+						{
+							issuers.Add(X509Name.GetInstance(genNames[j].Name.ToAsn1Object()));
+						}
+						catch (IOException e)
+						{
+							throw new Exception(
+								"CRL issuer information from distribution point cannot be decoded.",
+								e);
+						}
+					}
+				}
+			}
+			else
+			{
+				/*
+				 * certificate issuer is CRL issuer, distributionPoint field MUST be
+				 * present.
+				 */
+				if (dp.DistributionPointName == null)
+				{
+					throw new Exception(
+						"CRL issuer is omitted from distribution point but no distributionPoint field present.");
+				}
+
+				// add and check issuer principals
+				for (IEnumerator it = issuerPrincipals.GetEnumerator(); it.MoveNext(); )
+				{
+					issuers.Add((X509Name)it.Current);
+				}
+			}
+			// TODO: is not found although this should correctly add the rel name. selector of Sun is buggy here or PKI test case is invalid
+			// distributionPoint
+			//        if (dp.getDistributionPoint() != null)
+			//        {
+			//            // look for nameRelativeToCRLIssuer
+			//            if (dp.getDistributionPoint().getType() == DistributionPointName.NAME_RELATIVE_TO_CRL_ISSUER)
+			//            {
+			//                // append fragment to issuer, only one
+			//                // issuer can be there, if this is given
+			//                if (issuers.size() != 1)
+			//                {
+			//                    throw new AnnotatedException(
+			//                        "nameRelativeToCRLIssuer field is given but more than one CRL issuer is given.");
+			//                }
+			//                DEREncodable relName = dp.getDistributionPoint().getName();
+			//                Iterator it = issuers.iterator();
+			//                List issuersTemp = new ArrayList(issuers.size());
+			//                while (it.hasNext())
+			//                {
+			//                    Enumeration e = null;
+			//                    try
+			//                    {
+			//                        e = ASN1Sequence.getInstance(
+			//                            new ASN1InputStream(((X500Principal) it.next())
+			//                                .getEncoded()).readObject()).getObjects();
+			//                    }
+			//                    catch (IOException ex)
+			//                    {
+			//                        throw new AnnotatedException(
+			//                            "Cannot decode CRL issuer information.", ex);
+			//                    }
+			//                    ASN1EncodableVector v = new ASN1EncodableVector();
+			//                    while (e.hasMoreElements())
+			//                    {
+			//                        v.add((DEREncodable) e.nextElement());
+			//                    }
+			//                    v.add(relName);
+			//                    issuersTemp.add(new X500Principal(new DERSequence(v)
+			//                        .getDEREncoded()));
+			//                }
+			//                issuers.clear();
+			//                issuers.addAll(issuersTemp);
+			//            }
+			//        }
+
+			selector.Issuers = issuers;
+		}
+
+		/**
+		 * Fetches complete CRLs according to RFC 3280.
+		 *
+		 * @param dp The distribution point for which the complete CRL
+		 * @param cert The <code>X509Certificate</code> or
+		 *            {@link org.bouncycastle.x509.X509AttributeCertificate} for
+		 *            which the CRL should be searched.
+		 * @param currentDate The date for which the delta CRLs must be valid.
+		 * @param paramsPKIX The extended PKIX parameters.
+		 * @return A <code>Set</code> of <code>X509CRL</code>s with complete
+		 *         CRLs.
+		 * @throws Exception if an exception occurs while picking the CRLs
+		 *             or no CRLs are found.
+		 */
+		internal static ISet GetCompleteCrls(
+			DistributionPoint	dp,
+			object				cert,
+			DateTime			currentDate,
+			PkixParameters		paramsPKIX)
+		{
+			X509CrlStoreSelector crlselect = new X509CrlStoreSelector();
+			try
+			{
+				ISet issuers = new HashSet();
+				if (cert is X509V2AttributeCertificate)
+				{
+					issuers.Add(((X509V2AttributeCertificate)cert)
+						.Issuer.GetPrincipals()[0]);
+				}
+				else
+				{
+					issuers.Add(GetIssuerPrincipal(cert));
+				}
+				PkixCertPathValidatorUtilities.GetCrlIssuersFromDistributionPoint(dp, issuers, crlselect, paramsPKIX);
+			}
+			catch (Exception e)
+			{
+				new Exception("Could not get issuer information from distribution point.", e);
+			}
+
+			if (cert is X509Certificate)
+			{
+				crlselect.CertificateChecking = (X509Certificate)cert;
+			}
+			else if (cert is X509V2AttributeCertificate)
+			{
+				crlselect.AttrCertChecking = (IX509AttributeCertificate)cert;
+			}
+
+			crlselect.CompleteCrlEnabled = true;
+			ISet crls = CrlUtilities.FindCrls(crlselect, paramsPKIX, currentDate);
+
+			if (crls.IsEmpty)
+			{
+				if (cert is IX509AttributeCertificate)
+				{
+					IX509AttributeCertificate aCert = (IX509AttributeCertificate)cert;
+
+					throw new Exception("No CRLs found for issuer \"" + aCert.Issuer.GetPrincipals()[0] + "\"");
+				}
+				else
+				{
+					X509Certificate xCert = (X509Certificate)cert;
+
+					throw new Exception("No CRLs found for issuer \"" + xCert.IssuerDN + "\"");
+				}
+			}
+
+			return crls;
+		}
+
+		/**
+		 * Fetches delta CRLs according to RFC 3280 section 5.2.4.
+		 *
+		 * @param currentDate The date for which the delta CRLs must be valid.
+		 * @param paramsPKIX The extended PKIX parameters.
+		 * @param completeCRL The complete CRL the delta CRL is for.
+		 * @return A <code>Set</code> of <code>X509CRL</code>s with delta CRLs.
+		 * @throws Exception if an exception occurs while picking the delta
+		 *             CRLs.
+		 */
+		internal static ISet GetDeltaCrls(
+			DateTime		currentDate,
+			PkixParameters	paramsPKIX,
+			X509Crl			completeCRL)
+		{
+			X509CrlStoreSelector deltaSelect = new X509CrlStoreSelector();
+
+			// 5.2.4 (a)
+			try
+			{
+                IList deltaSelectIssuer = Platform.CreateArrayList();
+				deltaSelectIssuer.Add(completeCRL.IssuerDN);
+				deltaSelect.Issuers = deltaSelectIssuer;
+			}
+			catch (IOException e)
+			{
+				new Exception("Cannot extract issuer from CRL.", e);
+			}
+
+			BigInteger completeCRLNumber = null;
+			try
+			{
+				Asn1Object asn1Object = GetExtensionValue(completeCRL, X509Extensions.CrlNumber);
+				if (asn1Object != null)
+				{
+					completeCRLNumber = CrlNumber.GetInstance(asn1Object).PositiveValue;
+				}
+			}
+			catch (Exception e)
+			{
+				throw new Exception(
+					"CRL number extension could not be extracted from CRL.", e);
+			}
+
+			// 5.2.4 (b)
+			byte[] idp = null;
+
+			try
+			{
+				Asn1Object obj = GetExtensionValue(completeCRL, X509Extensions.IssuingDistributionPoint);
+				if (obj != null)
+				{
+					idp = obj.GetDerEncoded();
+				}
+			}
+			catch (Exception e)
+			{
+				throw new Exception(
+					"Issuing distribution point extension value could not be read.",
+					e);
+			}
+
+			// 5.2.4 (d)
+
+			deltaSelect.MinCrlNumber = (completeCRLNumber == null)
+				?	null
+				:	completeCRLNumber.Add(BigInteger.One);
+
+			deltaSelect.IssuingDistributionPoint = idp;
+			deltaSelect.IssuingDistributionPointEnabled = true;
+
+			// 5.2.4 (c)
+			deltaSelect.MaxBaseCrlNumber = completeCRLNumber;
+
+			// find delta CRLs
+			ISet temp = CrlUtilities.FindCrls(deltaSelect, paramsPKIX, currentDate);
+
+			ISet result = new HashSet();
+
+			foreach (X509Crl crl in temp)
+			{
+				if (isDeltaCrl(crl))
+				{
+					result.Add(crl);
+				}
+			}
+
+			return result;
+		}
+
+		private static bool isDeltaCrl(
+			X509Crl crl)
+		{
+			ISet critical = crl.GetCriticalExtensionOids();
+
+			return critical.Contains(X509Extensions.DeltaCrlIndicator.Id);
+		}
+
+		internal static ICollection FindCertificates(
+			X509AttrCertStoreSelector	certSelect,
+			IList						certStores)
+		{
+			ISet certs = new HashSet();
+
+			foreach (IX509Store certStore in certStores)
+			{
+				try
+				{
+//					certs.AddAll(certStore.GetMatches(certSelect));
+					foreach (X509V2AttributeCertificate ac in certStore.GetMatches(certSelect))
+					{
+						certs.Add(ac);
+					}
+				}
+				catch (Exception e)
+				{
+					throw new Exception(
+						"Problem while picking certificates from X.509 store.", e);
+				}
+			}
+
+			return certs;
+		}
+
+		internal static void AddAdditionalStoresFromCrlDistributionPoint(
+			CrlDistPoint	crldp,
+			PkixParameters	pkixParams)
+		{
+			if (crldp != null)
+			{
+				DistributionPoint[] dps = null;
+				try
+				{
+					dps = crldp.GetDistributionPoints();
+				}
+				catch (Exception e)
+				{
+					throw new Exception(
+						"Distribution points could not be read.", e);
+				}
+				for (int i = 0; i < dps.Length; i++)
+				{
+					DistributionPointName dpn = dps[i].DistributionPointName;
+					// look for URIs in fullName
+					if (dpn != null)
+					{
+						if (dpn.PointType == DistributionPointName.FullName)
+						{
+							GeneralName[] genNames = GeneralNames.GetInstance(
+								dpn.Name).GetNames();
+							// look for an URI
+							for (int j = 0; j < genNames.Length; j++)
+							{
+								if (genNames[j].TagNo == GeneralName.UniformResourceIdentifier)
+								{
+									string location = DerIA5String.GetInstance(
+										genNames[j].Name).GetString();
+									PkixCertPathValidatorUtilities.AddAdditionalStoreFromLocation(
+										location, pkixParams);
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+
+		internal static bool ProcessCertD1i(
+			int					index,
+			IList[]				policyNodes,
+			DerObjectIdentifier	pOid,
+			ISet				pq)
+		{
+			IList policyNodeVec = policyNodes[index - 1];
+
+			for (int j = 0; j < policyNodeVec.Count; j++)
+			{
+				PkixPolicyNode node = (PkixPolicyNode)policyNodeVec[j];
+				ISet expectedPolicies = node.ExpectedPolicies;
+
+				if (expectedPolicies.Contains(pOid.Id))
+				{
+					ISet childExpectedPolicies = new HashSet();
+					childExpectedPolicies.Add(pOid.Id);
+
+                    PkixPolicyNode child = new PkixPolicyNode(Platform.CreateArrayList(),
+						index,
+						childExpectedPolicies,
+						node,
+						pq,
+						pOid.Id,
+						false);
+					node.AddChild(child);
+					policyNodes[index].Add(child);
+
+					return true;
+				}
+			}
+
+			return false;
+		}
+
+		internal static void ProcessCertD1ii(
+			int					index,
+			IList[]				policyNodes,
+			DerObjectIdentifier _poid,
+			ISet				_pq)
+		{
+			IList policyNodeVec = policyNodes[index - 1];
+
+			for (int j = 0; j < policyNodeVec.Count; j++)
+			{
+				PkixPolicyNode _node = (PkixPolicyNode)policyNodeVec[j];
+
+				if (ANY_POLICY.Equals(_node.ValidPolicy))
+				{
+					ISet _childExpectedPolicies = new HashSet();
+					_childExpectedPolicies.Add(_poid.Id);
+
+                    PkixPolicyNode _child = new PkixPolicyNode(Platform.CreateArrayList(),
+						index,
+						_childExpectedPolicies,
+						_node,
+						_pq,
+						_poid.Id,
+						false);
+					_node.AddChild(_child);
+					policyNodes[index].Add(_child);
+					return;
+				}
+			}
+		}
+
+		/**
+		* Find the issuer certificates of a given certificate.
+		*
+		* @param cert
+		*            The certificate for which an issuer should be found.
+		* @param pkixParams
+		* @return A <code>Collection</code> object containing the issuer
+		*         <code>X509Certificate</code>s. Never <code>null</code>.
+		*
+		* @exception Exception
+		*                if an error occurs.
+		*/
+		internal static ICollection FindIssuerCerts(
+			X509Certificate			cert,
+			PkixBuilderParameters	pkixParams)
+		{
+			X509CertStoreSelector certSelect = new X509CertStoreSelector();
+			ISet certs = new HashSet();
+			try
+			{
+				certSelect.Subject = cert.IssuerDN;
+			}
+			catch (IOException ex)
+			{
+				throw new Exception(
+					"Subject criteria for certificate selector to find issuer certificate could not be set.", ex);
+			}
+
+			try
+			{
+                certs.AddAll(PkixCertPathValidatorUtilities.FindCertificates(certSelect, pkixParams.GetStores()));
+                certs.AddAll(PkixCertPathValidatorUtilities.FindCertificates(certSelect, pkixParams.GetAdditionalStores()));
+			}
+			catch (Exception e)
+			{
+				throw new Exception("Issuer certificate cannot be searched.", e);
+			}
+
+			return certs;
+		}
+
+		/// <summary>
+		/// Extract the value of the given extension, if it exists.
+		/// </summary>
+		/// <param name="ext">The extension object.</param>
+		/// <param name="oid">The object identifier to obtain.</param>
+		/// <returns>Asn1Object</returns>
+		/// <exception cref="Exception">if the extension cannot be read.</exception>
+		internal static Asn1Object GetExtensionValue(
+			IX509Extension		ext,
+			DerObjectIdentifier	oid)
+		{
+			Asn1OctetString bytes = ext.GetExtensionValue(oid);
+
+			if (bytes == null)
+				return null;
+
+			return X509ExtensionUtilities.FromExtensionValue(bytes);
+		}
+	}
+}
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
new file mode 100644
index 000000000..9f01e8765
--- /dev/null
+++ b/Crypto/src/pkix/PkixNameConstraintValidatorException.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Org.BouncyCastle.Pkix
+{
+    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
new file mode 100644
index 000000000..bae657d90
--- /dev/null
+++ b/Crypto/src/pkix/Rfc3280CertPathUtilities.cs
@@ -0,0 +1,2448 @@
+using System;
+using System.Collections;
+using System.Globalization;
+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;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Utilities.Date;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+	public class Rfc3280CertPathUtilities
+	{
+		private static readonly PkixCrlUtilities CrlUtilities = new PkixCrlUtilities();
+
+		internal static readonly string ANY_POLICY = "2.5.29.32.0";
+
+		// key usage bits
+		internal static readonly int KEY_CERT_SIGN = 5;
+		internal static readonly int CRL_SIGN = 6;
+
+		/**
+		* If the complete CRL includes an issuing distribution point (IDP) CRL
+		* extension check the following:
+		* <p>
+		* (i) If the distribution point name is present in the IDP CRL extension
+		* and the distribution field is present in the DP, then verify that one of
+		* the names in the IDP matches one of the names in the DP. If the
+		* distribution point name is present in the IDP CRL extension and the
+		* distribution field is omitted from the DP, then verify that one of the
+		* names in the IDP matches one of the names in the cRLIssuer field of the
+		* DP.
+		* </p>
+		* <p>
+		* (ii) If the onlyContainsUserCerts boolean is asserted in the IDP CRL
+		* extension, verify that the certificate does not include the basic
+		* constraints extension with the cA boolean asserted.
+		* </p>
+		* <p>
+		* (iii) If the onlyContainsCACerts boolean is asserted in the IDP CRL
+		* extension, verify that the certificate includes the basic constraints
+		* extension with the cA boolean asserted.
+		* </p>
+		* <p>
+		* (iv) Verify that the onlyContainsAttributeCerts boolean is not asserted.
+		* </p>
+		*
+		* @param dp   The distribution point.
+		* @param cert The certificate.
+		* @param crl  The CRL.
+		* @throws AnnotatedException if one of the conditions is not met or an error occurs.
+		*/
+		internal static void ProcessCrlB2(
+			DistributionPoint	dp,
+			object				cert,
+			X509Crl				crl)
+		{
+			IssuingDistributionPoint idp = null;
+			try
+			{
+				idp = IssuingDistributionPoint.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(crl, X509Extensions.IssuingDistributionPoint));
+			}
+			catch (Exception e)
+			{
+				throw new Exception("0 Issuing distribution point extension could not be decoded.", e);
+			}
+			// (b) (2) (i)
+			// distribution point name is present
+			if (idp != null)
+			{
+				if (idp.DistributionPoint != null)
+				{
+					// make list of names
+					DistributionPointName dpName = IssuingDistributionPoint.GetInstance(idp).DistributionPoint;
+					IList names = Platform.CreateArrayList();
+
+					if (dpName.PointType == DistributionPointName.FullName)
+					{
+						GeneralName[] genNames = GeneralNames.GetInstance(dpName.Name).GetNames();
+						for (int j = 0; j < genNames.Length; j++)
+						{
+							names.Add(genNames[j]);
+						}
+					}
+					if (dpName.PointType == DistributionPointName.NameRelativeToCrlIssuer)
+					{
+						Asn1EncodableVector vec = new Asn1EncodableVector();
+						try
+						{
+							IEnumerator e = Asn1Sequence.GetInstance(
+								Asn1Sequence.FromByteArray(crl.IssuerDN.GetEncoded())).GetEnumerator();
+							while (e.MoveNext())
+							{
+								vec.Add((Asn1Encodable)e.Current);
+							}
+						}
+						catch (IOException e)
+						{
+							throw new Exception("Could not read CRL issuer.", e);
+						}
+						vec.Add(dpName.Name);
+						names.Add(new GeneralName(X509Name.GetInstance(new DerSequence(vec))));
+					}
+					bool matches = false;
+					// verify that one of the names in the IDP matches one
+					// of the names in the DP.
+					if (dp.DistributionPointName != null)
+					{
+						dpName = dp.DistributionPointName;
+						GeneralName[] genNames = null;
+						if (dpName.PointType == DistributionPointName.FullName)
+						{
+							genNames = GeneralNames.GetInstance(dpName.Name).GetNames();
+						}
+						if (dpName.PointType == DistributionPointName.NameRelativeToCrlIssuer)
+						{
+							if (dp.CrlIssuer != null)
+							{
+								genNames = dp.CrlIssuer.GetNames();
+							}
+							else
+							{
+								genNames = new GeneralName[1];
+								try
+								{
+									genNames[0] = new GeneralName(
+										PkixCertPathValidatorUtilities.GetIssuerPrincipal(cert));
+								}
+								catch (IOException e)
+								{
+									throw new Exception("Could not read certificate issuer.", e);
+								}
+							}
+							for (int j = 0; j < genNames.Length; j++)
+							{
+								IEnumerator e = Asn1Sequence.GetInstance(genNames[j].Name.ToAsn1Object()).GetEnumerator();
+								Asn1EncodableVector vec = new Asn1EncodableVector();
+								while (e.MoveNext())
+								{
+									vec.Add((Asn1Encodable)e.Current);
+								}
+								vec.Add(dpName.Name);
+								genNames[j] = new GeneralName(X509Name.GetInstance(new DerSequence(vec)));
+							}
+						}
+						if (genNames != null)
+						{
+							for (int j = 0; j < genNames.Length; j++)
+							{
+								if (names.Contains(genNames[j]))
+								{
+									matches = true;
+									break;
+								}
+							}
+						}
+						if (!matches)
+						{
+							throw new Exception(
+								"No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+						}
+					}
+						// verify that one of the names in
+						// the IDP matches one of the names in the cRLIssuer field of
+						// the DP
+					else
+					{
+						if (dp.CrlIssuer == null)
+						{
+							throw new Exception("Either the cRLIssuer or the distributionPoint field must "
+								+ "be contained in DistributionPoint.");
+						}
+						GeneralName[] genNames = dp.CrlIssuer.GetNames();
+						for (int j = 0; j < genNames.Length; j++)
+						{
+							if (names.Contains(genNames[j]))
+							{
+								matches = true;
+								break;
+							}
+						}
+						if (!matches)
+						{
+							throw new Exception(
+								"No match for certificate CRL issuing distribution point name to cRLIssuer CRL distribution point.");
+						}
+					}
+				}
+				BasicConstraints bc = null;
+				try
+				{
+					bc = BasicConstraints.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(
+						(IX509Extension)cert, X509Extensions.BasicConstraints));
+				}
+				catch (Exception e)
+				{
+					throw new Exception("Basic constraints extension could not be decoded.", e);
+				}
+
+				//if (cert is X509Certificate)
+				{
+					// (b) (2) (ii)
+					if (idp.OnlyContainsUserCerts && ((bc != null) && bc.IsCA()))
+					{
+						throw new Exception("CA Cert CRL only contains user certificates.");
+					}
+
+					// (b) (2) (iii)
+					if (idp.OnlyContainsCACerts && (bc == null || !bc.IsCA()))
+					{
+						throw new Exception("End CRL only contains CA certificates.");
+					}
+				}
+
+				// (b) (2) (iv)
+				if (idp.OnlyContainsAttributeCerts)
+				{
+					throw new Exception("onlyContainsAttributeCerts boolean is asserted.");
+				}
+			}
+		}
+
+		internal static void ProcessCertBC(
+			PkixCertPath				certPath,
+			int							index,
+			PkixNameConstraintValidator	nameConstraintValidator)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+			int n = certs.Count;
+			// i as defined in the algorithm description
+			int i = n - index;
+			//
+			// (b), (c) permitted and excluded subtree checking.
+			//
+			if (!(PkixCertPathValidatorUtilities.IsSelfIssued(cert) && (i < n)))
+			{
+				X509Name principal = cert.SubjectDN;
+				Asn1InputStream aIn = new Asn1InputStream(principal.GetEncoded());
+				Asn1Sequence dns;
+
+				try
+				{
+					dns = DerSequence.GetInstance(aIn.ReadObject());
+				}
+				catch (Exception e)
+				{
+					throw new PkixCertPathValidatorException(
+						"Exception extracting subject name when checking subtrees.", e, certPath, index);
+				}
+
+				try
+				{
+					nameConstraintValidator.CheckPermittedDN(dns);
+					nameConstraintValidator.CheckExcludedDN(dns);
+				}
+				catch (PkixNameConstraintValidatorException e)
+				{
+					throw new PkixCertPathValidatorException(
+						"Subtree check for certificate subject failed.", e, certPath, index);
+				}
+
+				GeneralNames altName = null;
+				try
+				{
+					altName = GeneralNames.GetInstance(
+						PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.SubjectAlternativeName));
+				}
+				catch (Exception e)
+				{
+					throw new PkixCertPathValidatorException(
+						"Subject alternative name extension could not be decoded.", e, certPath, index);
+				}
+
+				IList emails = X509Name.GetInstance(dns).GetValueList(X509Name.EmailAddress);
+				foreach (string email in emails)
+				{
+					GeneralName emailAsGeneralName = new GeneralName(GeneralName.Rfc822Name, email);
+					try
+					{
+						nameConstraintValidator.checkPermitted(emailAsGeneralName);
+						nameConstraintValidator.checkExcluded(emailAsGeneralName);
+					}
+					catch (PkixNameConstraintValidatorException ex)
+					{
+						throw new PkixCertPathValidatorException(
+							"Subtree check for certificate subject alternative email failed.", ex, certPath, index);
+					}
+				}
+				if (altName != null)
+				{
+					GeneralName[] genNames = null;
+					try
+					{
+						genNames = altName.GetNames();
+					}
+					catch (Exception e)
+					{
+						throw new PkixCertPathValidatorException(
+							"Subject alternative name contents could not be decoded.", e, certPath, index);
+					}
+					foreach (GeneralName genName in genNames)
+					{
+						try
+						{
+							nameConstraintValidator.checkPermitted(genName);
+							nameConstraintValidator.checkExcluded(genName);
+						}
+						catch (PkixNameConstraintValidatorException e)
+						{
+							throw new PkixCertPathValidatorException(
+								"Subtree check for certificate subject alternative name failed.", e, certPath, index);
+						}
+					}
+				}
+			}
+		}
+
+		internal static void PrepareNextCertA(
+			PkixCertPath	certPath,
+			int				index)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+			//
+			//
+			// (a) check the policy mappings
+			//
+			Asn1Sequence pm = null;
+			try
+			{
+				pm = Asn1Sequence.GetInstance(
+					PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyMappings));
+			}
+			catch (Exception ex)
+			{
+				throw new PkixCertPathValidatorException(
+					"Policy mappings extension could not be decoded.", ex, certPath, index);
+			}
+			if (pm != null)
+			{
+				Asn1Sequence mappings = pm;
+
+				for (int j = 0; j < mappings.Count; j++)
+				{
+					DerObjectIdentifier issuerDomainPolicy = null;
+					DerObjectIdentifier subjectDomainPolicy = null;
+					try
+					{
+						Asn1Sequence mapping = DerSequence.GetInstance(mappings[j]);
+
+						issuerDomainPolicy = DerObjectIdentifier.GetInstance(mapping[0]);
+						subjectDomainPolicy = DerObjectIdentifier.GetInstance(mapping[1]);
+					}
+					catch (Exception e)
+					{
+						throw new PkixCertPathValidatorException(
+							"Policy mappings extension contents could not be decoded.", e, certPath, index);
+					}
+
+					if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(issuerDomainPolicy.Id))
+						throw new PkixCertPathValidatorException(
+							"IssuerDomainPolicy is anyPolicy", null, certPath, index);
+
+					if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(subjectDomainPolicy.Id))
+						throw new PkixCertPathValidatorException(
+							"SubjectDomainPolicy is anyPolicy,", null, certPath, index);
+				}
+			}
+		}
+
+		internal static PkixPolicyNode ProcessCertD(
+			PkixCertPath	certPath,
+			int				index,
+			ISet			acceptablePolicies,
+			PkixPolicyNode	validPolicyTree,
+			IList[]			policyNodes,
+			int				inhibitAnyPolicy)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+			int n = certs.Count;
+			// i as defined in the algorithm description
+			int i = n - index;
+			//
+			// (d) policy Information checking against initial policy and
+			// policy mapping
+			//
+			Asn1Sequence certPolicies = null;
+			try
+			{
+				certPolicies = DerSequence.GetInstance(
+					PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.CertificatePolicies));
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathValidatorException(
+					"Could not read certificate policies extension from certificate.", e, certPath, index);
+			}
+			if (certPolicies != null && validPolicyTree != null)
+			{
+				//
+				// (d) (1)
+				//
+				ISet pols = new HashSet();
+
+				foreach (Asn1Encodable ae in certPolicies)
+				{
+					PolicyInformation pInfo = PolicyInformation.GetInstance(ae.ToAsn1Object());
+					DerObjectIdentifier pOid = pInfo.PolicyIdentifier;
+
+					pols.Add(pOid.Id);
+
+					if (!Rfc3280CertPathUtilities.ANY_POLICY.Equals(pOid.Id))
+					{
+						ISet pq = null;
+						try
+						{
+							pq = PkixCertPathValidatorUtilities.GetQualifierSet(pInfo.PolicyQualifiers);
+						}
+						catch (PkixCertPathValidatorException ex)
+						{
+							throw new PkixCertPathValidatorException(
+								"Policy qualifier info set could not be build.", ex, certPath, index);
+						}
+
+						bool match = PkixCertPathValidatorUtilities.ProcessCertD1i(i, policyNodes, pOid, pq);
+
+						if (!match)
+						{
+							PkixCertPathValidatorUtilities.ProcessCertD1ii(i, policyNodes, pOid, pq);
+						}
+					}
+				}
+
+				if (acceptablePolicies.IsEmpty || acceptablePolicies.Contains(Rfc3280CertPathUtilities.ANY_POLICY))
+				{
+					acceptablePolicies.Clear();
+					acceptablePolicies.AddAll(pols);
+				}
+				else
+				{
+					ISet t1 = new HashSet();
+
+					foreach (object o in acceptablePolicies)
+					{
+						if (pols.Contains(o))
+						{
+							t1.Add(o);
+						}
+					}
+					acceptablePolicies.Clear();
+					acceptablePolicies.AddAll(t1);
+				}
+
+				//
+				// (d) (2)
+				//
+				if ((inhibitAnyPolicy > 0) || ((i < n) && PkixCertPathValidatorUtilities.IsSelfIssued(cert)))
+				{
+					foreach (Asn1Encodable ae in certPolicies)
+					{
+						PolicyInformation pInfo = PolicyInformation.GetInstance(ae.ToAsn1Object());
+						if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(pInfo.PolicyIdentifier.Id))
+						{
+							ISet _apq = PkixCertPathValidatorUtilities.GetQualifierSet(pInfo.PolicyQualifiers);
+							IList _nodes = policyNodes[i - 1];
+
+							for (int k = 0; k < _nodes.Count; k++)
+							{
+								PkixPolicyNode _node = (PkixPolicyNode)_nodes[k];
+
+								IEnumerator  _policySetIter = _node.ExpectedPolicies.GetEnumerator();
+								while (_policySetIter.MoveNext())
+								{
+									object _tmp = _policySetIter.Current;
+
+									string _policy;
+									if (_tmp is string)
+									{
+										_policy = (string)_tmp;
+									}
+									else if (_tmp is DerObjectIdentifier)
+									{
+										_policy = ((DerObjectIdentifier)_tmp).Id;
+									}
+									else
+									{
+										continue;
+									}
+
+									bool _found = false;
+
+									foreach (PkixPolicyNode _child in _node.Children)
+									{
+										if (_policy.Equals(_child.ValidPolicy))
+										{
+											_found = true;
+										}
+									}
+
+									if (!_found)
+									{
+										ISet _newChildExpectedPolicies = new HashSet();
+										_newChildExpectedPolicies.Add(_policy);
+
+										PkixPolicyNode _newChild = new PkixPolicyNode(Platform.CreateArrayList(), i,
+											_newChildExpectedPolicies, _node, _apq, _policy, false);
+										_node.AddChild(_newChild);
+										policyNodes[i].Add(_newChild);
+									}
+								}
+							}
+							break;
+						}
+					}
+				}
+
+				PkixPolicyNode _validPolicyTree = validPolicyTree;
+				//
+				// (d) (3)
+				//
+				for (int j = (i - 1); j >= 0; j--)
+				{
+					IList nodes = policyNodes[j];
+
+					for (int k = 0; k < nodes.Count; k++)
+					{
+						PkixPolicyNode node = (PkixPolicyNode)nodes[k];
+						if (!node.HasChildren)
+						{
+							_validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(_validPolicyTree, policyNodes,
+								node);
+							if (_validPolicyTree == null)
+							{
+								break;
+							}
+						}
+					}
+				}
+
+				//
+				// d (4)
+				//
+				ISet criticalExtensionOids = cert.GetCriticalExtensionOids();
+
+				if (criticalExtensionOids != null)
+				{
+					bool critical = criticalExtensionOids.Contains(X509Extensions.CertificatePolicies.Id);
+
+					IList nodes = policyNodes[i];
+					for (int j = 0; j < nodes.Count; j++)
+					{
+						PkixPolicyNode node = (PkixPolicyNode)nodes[j];
+						node.IsCritical = critical;
+					}
+				}
+				return _validPolicyTree;
+			}
+			return null;
+		}
+
+		/**
+		* If the DP includes cRLIssuer, then verify that the issuer field in the
+		* complete CRL matches cRLIssuer in the DP and that the complete CRL
+		* contains an
+		*      g distribution point extension with the indirectCRL
+		* boolean asserted. Otherwise, verify that the CRL issuer matches the
+		* certificate issuer.
+		*
+		* @param dp   The distribution point.
+		* @param cert The certificate ot attribute certificate.
+		* @param crl  The CRL for <code>cert</code>.
+		* @throws AnnotatedException if one of the above conditions does not apply or an error
+		*                            occurs.
+		*/
+		internal static void ProcessCrlB1(
+			DistributionPoint	dp,
+			object				cert,
+			X509Crl				crl)
+		{
+			Asn1Object idp = PkixCertPathValidatorUtilities.GetExtensionValue(
+				crl, X509Extensions.IssuingDistributionPoint);
+
+			bool isIndirect = false;
+			if (idp != null)
+			{
+				if (IssuingDistributionPoint.GetInstance(idp).IsIndirectCrl)
+				{
+					isIndirect = true;
+				}
+			}
+			byte[] issuerBytes = crl.IssuerDN.GetEncoded();
+
+			bool matchIssuer = false;
+			if (dp.CrlIssuer != null)
+			{
+				GeneralName[] genNames = dp.CrlIssuer.GetNames();
+				for (int j = 0; j < genNames.Length; j++)
+				{
+					if (genNames[j].TagNo == GeneralName.DirectoryName)
+					{
+						try
+						{
+							if (Org.BouncyCastle.Utilities.Arrays.AreEqual(genNames[j].Name.ToAsn1Object().GetEncoded(), issuerBytes))
+							{
+								matchIssuer = true;
+							}
+						}
+						catch (IOException e)
+						{
+							throw new Exception(
+								"CRL issuer information from distribution point cannot be decoded.", e);
+						}
+					}
+				}
+				if (matchIssuer && !isIndirect)
+				{
+					throw new Exception("Distribution point contains cRLIssuer field but CRL is not indirect.");
+				}
+				if (!matchIssuer)
+				{
+					throw new Exception("CRL issuer of CRL does not match CRL issuer of distribution point.");
+				}
+			}
+			else
+			{
+				if (crl.IssuerDN.Equivalent(PkixCertPathValidatorUtilities.GetIssuerPrincipal(cert), true))
+				{
+					matchIssuer = true;
+				}
+			}
+			if (!matchIssuer)
+			{
+				throw new Exception("Cannot find matching CRL issuer for certificate.");
+			}
+		}
+
+		internal static ReasonsMask ProcessCrlD(
+			X509Crl				crl,
+			DistributionPoint	dp)
+			//throws AnnotatedException
+		{
+			IssuingDistributionPoint idp = null;
+			try
+			{
+				idp = IssuingDistributionPoint.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(crl, X509Extensions.IssuingDistributionPoint));
+			}
+			catch (Exception e)
+			{
+				throw new Exception("issuing distribution point extension could not be decoded.", e);
+			}
+
+			// (d) (1)
+			if (idp != null && idp.OnlySomeReasons != null && dp.Reasons != null)
+			{
+				return new ReasonsMask(dp.Reasons.IntValue).Intersect(new ReasonsMask(idp.OnlySomeReasons
+					.IntValue));
+			}
+			// (d) (4)
+			if ((idp == null || idp.OnlySomeReasons == null) && dp.Reasons == null)
+			{
+				return ReasonsMask.AllReasons;
+			}
+
+			// (d) (2) and (d)(3)
+
+			ReasonsMask dpReasons = null;
+
+			if (dp.Reasons == null)
+			{
+				dpReasons = ReasonsMask.AllReasons;
+			}
+			else
+			{
+				dpReasons = new ReasonsMask(dp.Reasons.IntValue);
+			}
+
+			ReasonsMask idpReasons = null;
+
+			if (idp == null)
+			{
+				idpReasons = ReasonsMask.AllReasons;
+			}
+			else
+			{
+				idpReasons = new ReasonsMask(idp.OnlySomeReasons.IntValue);
+			}
+
+			return dpReasons.Intersect(idpReasons);
+		}
+
+		/**
+		* Obtain and validate the certification path for the complete CRL issuer.
+		* If a key usage extension is present in the CRL issuer's certificate,
+		* verify that the cRLSign bit is set.
+		*
+		* @param crl                CRL which contains revocation information for the certificate
+		*                           <code>cert</code>.
+		* @param cert               The attribute certificate or certificate to check if it is
+		*                           revoked.
+		* @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+		* @param defaultCRLSignKey  The public key of the issuer certificate
+		*                           <code>defaultCRLSignCert</code>.
+		* @param paramsPKIX         paramsPKIX PKIX parameters.
+		* @param certPathCerts      The certificates on the certification path.
+		* @return A <code>Set</code> with all keys of possible CRL issuer
+		*         certificates.
+		* @throws AnnotatedException if the CRL is not valid or the status cannot be checked or
+		*                            some error occurs.
+		*/
+		internal static ISet ProcessCrlF(
+			X509Crl					crl,
+			object					cert,
+			X509Certificate			defaultCRLSignCert,
+			AsymmetricKeyParameter	defaultCRLSignKey,
+			PkixParameters			paramsPKIX,
+			IList					certPathCerts)
+		{
+			// (f)
+
+			// get issuer from CRL
+			X509CertStoreSelector selector = new X509CertStoreSelector();
+			try
+			{
+				selector.Subject = crl.IssuerDN;
+			}
+			catch (IOException e)
+			{
+				throw new Exception(
+					"Subject criteria for certificate selector to find issuer certificate for CRL could not be set.", e);
+			}
+
+			// get CRL signing certs
+			IList coll = Platform.CreateArrayList();
+
+			try
+			{
+                CollectionUtilities.AddRange(coll, PkixCertPathValidatorUtilities.FindCertificates(selector, paramsPKIX.GetStores()));
+                CollectionUtilities.AddRange(coll, PkixCertPathValidatorUtilities.FindCertificates(selector, paramsPKIX.GetAdditionalStores()));
+			}
+			catch (Exception e)
+			{
+				throw new Exception("Issuer certificate for CRL cannot be searched.", e);
+			}
+
+			coll.Add(defaultCRLSignCert);
+
+			IEnumerator cert_it = coll.GetEnumerator();
+
+            IList validCerts = Platform.CreateArrayList();
+            IList validKeys = Platform.CreateArrayList();
+
+			while (cert_it.MoveNext())
+			{
+				X509Certificate signingCert = (X509Certificate)cert_it.Current;
+
+				/*
+				 * CA of the certificate, for which this CRL is checked, has also
+				 * signed CRL, so skip the path validation, because is already done
+				 */
+				if (signingCert.Equals(defaultCRLSignCert))
+				{
+					validCerts.Add(signingCert);
+					validKeys.Add(defaultCRLSignKey);
+					continue;
+				}
+				try
+				{
+//					CertPathBuilder builder = CertPathBuilder.GetInstance("PKIX");
+					PkixCertPathBuilder builder = new PkixCertPathBuilder();
+					selector = new X509CertStoreSelector();
+					selector.Certificate = signingCert;
+
+					PkixParameters temp = (PkixParameters)paramsPKIX.Clone();
+					temp.SetTargetCertConstraints(selector);
+
+					PkixBuilderParameters parameters = (PkixBuilderParameters)
+						PkixBuilderParameters.GetInstance(temp);
+
+					/*
+					 * if signingCert is placed not higher on the cert path a
+					 * dependency loop results. CRL for cert is checked, but
+					 * signingCert is needed for checking the CRL which is dependent
+					 * on checking cert because it is higher in the cert path and so
+					 * signing signingCert transitively. so, revocation is disabled,
+					 * forgery attacks of the CRL are detected in this outer loop
+					 * for all other it must be enabled to prevent forgery attacks
+					 */
+					if (certPathCerts.Contains(signingCert))
+					{
+						parameters.IsRevocationEnabled = false;
+					}
+					else
+					{
+						parameters.IsRevocationEnabled = true;
+					}
+					IList certs = builder.Build(parameters).CertPath.Certificates;
+					validCerts.Add(signingCert);
+					validKeys.Add(PkixCertPathValidatorUtilities.GetNextWorkingKey(certs, 0));
+				}
+				catch (PkixCertPathBuilderException e)
+				{
+					throw new Exception("Internal error.", e);
+				}
+				catch (PkixCertPathValidatorException e)
+				{
+					throw new Exception("Public key of issuer certificate of CRL could not be retrieved.", e);
+				}
+				//catch (Exception e)
+				//{
+				//    throw new Exception(e.Message);
+				//}
+			}
+
+			ISet checkKeys = new HashSet();
+
+			Exception lastException = null;
+			for (int i = 0; i < validCerts.Count; i++)
+			{
+				X509Certificate signCert = (X509Certificate)validCerts[i];
+				bool[] keyusage = signCert.GetKeyUsage();
+
+				if (keyusage != null && (keyusage.Length < 7 || !keyusage[CRL_SIGN]))
+				{
+					lastException = new Exception(
+						"Issuer certificate key usage extension does not permit CRL signing.");
+				}
+				else
+				{
+					checkKeys.Add(validKeys[i]);
+				}
+			}
+
+			if ((checkKeys.Count == 0) && lastException == null)
+			{
+				throw new Exception("Cannot find a valid issuer certificate.");
+			}
+			if ((checkKeys.Count == 0) && lastException != null)
+			{
+				throw lastException;
+			}
+
+			return checkKeys;
+		}
+
+		internal static AsymmetricKeyParameter ProcessCrlG(
+			X509Crl	crl,
+			ISet	keys)
+		{
+			Exception lastException = null;
+			foreach (AsymmetricKeyParameter key in keys)
+			{
+				try
+				{
+					crl.Verify(key);
+					return key;
+				}
+				catch (Exception e)
+				{
+					lastException = e;
+				}
+			}
+			throw new Exception("Cannot verify CRL.", lastException);
+		}
+
+		internal static X509Crl ProcessCrlH(
+			ISet					deltaCrls,
+			AsymmetricKeyParameter	key)
+		{
+			Exception lastException = null;
+			foreach (X509Crl crl in deltaCrls)
+			{
+				try
+				{
+					crl.Verify(key);
+					return crl;
+				}
+				catch (Exception e)
+				{
+					lastException = e;
+				}
+			}
+			if (lastException != null)
+			{
+				throw new Exception("Cannot verify delta CRL.", lastException);
+			}
+			return null;
+		}
+
+		/**
+		* Checks a distribution point for revocation information for the
+		* certificate <code>cert</code>.
+		*
+		* @param dp                 The distribution point to consider.
+		* @param paramsPKIX         PKIX parameters.
+		* @param cert               Certificate to check if it is revoked.
+		* @param validDate          The date when the certificate revocation status should be
+		*                           checked.
+		* @param defaultCRLSignCert The issuer certificate of the certificate <code>cert</code>.
+		* @param defaultCRLSignKey  The public key of the issuer certificate
+		*                           <code>defaultCRLSignCert</code>.
+		* @param certStatus         The current certificate revocation status.
+		* @param reasonMask         The reasons mask which is already checked.
+		* @param certPathCerts      The certificates of the certification path.
+		* @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+		*                            or some error occurs.
+		*/
+		private static void CheckCrl(
+			DistributionPoint dp,
+			PkixParameters paramsPKIX,
+			X509Certificate cert,
+			DateTime validDate,
+			X509Certificate defaultCRLSignCert,
+			AsymmetricKeyParameter defaultCRLSignKey,
+			CertStatus certStatus,
+			ReasonsMask reasonMask,
+			IList certPathCerts)
+			//throws AnnotatedException
+		{
+			DateTime currentDate = DateTime.UtcNow;
+
+			if (validDate.Ticks > currentDate.Ticks)
+			{
+				throw new Exception("Validation time is in future.");
+			}
+
+			// (a)
+			/*
+			 * We always get timely valid CRLs, so there is no step (a) (1).
+			 * "locally cached" CRLs are assumed to be in getStore(), additional
+			 * CRLs must be enabled in the ExtendedPKIXParameters and are in
+			 * getAdditionalStore()
+			 */
+
+			ISet crls = PkixCertPathValidatorUtilities.GetCompleteCrls(dp, cert, currentDate, paramsPKIX);
+			bool validCrlFound = false;
+			Exception lastException = null;
+
+			IEnumerator crl_iter = crls.GetEnumerator();
+
+			while (crl_iter.MoveNext() && certStatus.Status == CertStatus.Unrevoked && !reasonMask.IsAllReasons)
+			{
+				try
+				{
+					X509Crl crl = (X509Crl)crl_iter.Current;
+
+					// (d)
+					ReasonsMask interimReasonsMask = Rfc3280CertPathUtilities.ProcessCrlD(crl, dp);
+
+					// (e)
+					/*
+					 * The reasons mask is updated at the end, so only valid CRLs
+					 * can update it. If this CRL does not contain new reasons it
+					 * must be ignored.
+					 */
+					if (!interimReasonsMask.HasNewReasons(reasonMask))
+					{
+						continue;
+					}
+
+					// (f)
+					ISet keys = Rfc3280CertPathUtilities.ProcessCrlF(crl, cert, defaultCRLSignCert, defaultCRLSignKey,
+						paramsPKIX, certPathCerts);
+					// (g)
+					AsymmetricKeyParameter key = Rfc3280CertPathUtilities.ProcessCrlG(crl, keys);
+
+					X509Crl deltaCRL = null;
+
+					if (paramsPKIX.IsUseDeltasEnabled)
+					{
+						// get delta CRLs
+						ISet deltaCRLs = PkixCertPathValidatorUtilities.GetDeltaCrls(currentDate, paramsPKIX, crl);
+						// we only want one valid delta CRL
+						// (h)
+						deltaCRL = Rfc3280CertPathUtilities.ProcessCrlH(deltaCRLs, key);
+					}
+
+					/*
+					 * CRL must be be valid at the current time, not the validation
+					 * time. If a certificate is revoked with reason keyCompromise,
+					 * cACompromise, it can be used for forgery, also for the past.
+					 * This reason may not be contained in older CRLs.
+					 */
+
+					/*
+					 * in the chain model signatures stay valid also after the
+					 * certificate has been expired, so they do not have to be in
+					 * the CRL validity time
+					 */
+
+					if (paramsPKIX.ValidityModel != PkixParameters.ChainValidityModel)
+					{
+						/*
+						 * if a certificate has expired, but was revoked, it is not
+						 * more in the CRL, so it would be regarded as valid if the
+						 * first check is not done
+						 */
+						if (cert.NotAfter.Ticks < crl.ThisUpdate.Ticks)
+						{
+							throw new Exception("No valid CRL for current time found.");
+						}
+					}
+
+					Rfc3280CertPathUtilities.ProcessCrlB1(dp, cert, crl);
+
+					// (b) (2)
+					Rfc3280CertPathUtilities.ProcessCrlB2(dp, cert, crl);
+
+					// (c)
+					Rfc3280CertPathUtilities.ProcessCrlC(deltaCRL, crl, paramsPKIX);
+
+					// (i)
+					Rfc3280CertPathUtilities.ProcessCrlI(validDate, deltaCRL, cert, certStatus, paramsPKIX);
+
+					// (j)
+					Rfc3280CertPathUtilities.ProcessCrlJ(validDate, crl, cert, certStatus);
+
+					// (k)
+					if (certStatus.Status == CrlReason.RemoveFromCrl)
+					{
+						certStatus.Status = CertStatus.Unrevoked;
+					}
+
+					// update reasons mask
+					reasonMask.AddReasons(interimReasonsMask);
+
+					ISet criticalExtensions = crl.GetCriticalExtensionOids();
+
+					if (criticalExtensions != null)
+					{
+						criticalExtensions = new HashSet(criticalExtensions);
+						criticalExtensions.Remove(X509Extensions.IssuingDistributionPoint.Id);
+						criticalExtensions.Remove(X509Extensions.DeltaCrlIndicator.Id);
+
+						if (!criticalExtensions.IsEmpty)
+							throw new Exception("CRL contains unsupported critical extensions.");
+					}
+
+					if (deltaCRL != null)
+					{
+						criticalExtensions = deltaCRL.GetCriticalExtensionOids();
+						if (criticalExtensions != null)
+						{
+							criticalExtensions = new HashSet(criticalExtensions);
+							criticalExtensions.Remove(X509Extensions.IssuingDistributionPoint.Id);
+							criticalExtensions.Remove(X509Extensions.DeltaCrlIndicator.Id);
+
+							if (!criticalExtensions.IsEmpty)
+								throw new Exception("Delta CRL contains unsupported critical extension.");
+						}
+					}
+
+					validCrlFound = true;
+				}
+				catch (Exception e)
+				{
+					lastException = e;
+				}
+			}
+			if (!validCrlFound)
+			{
+				throw lastException;
+			}
+		}
+
+		/**
+		 * Checks a certificate if it is revoked.
+		 *
+		 * @param paramsPKIX       PKIX parameters.
+		 * @param cert             Certificate to check if it is revoked.
+		 * @param validDate        The date when the certificate revocation status should be
+		 *                         checked.
+		 * @param sign             The issuer certificate of the certificate <code>cert</code>.
+		 * @param workingPublicKey The public key of the issuer certificate <code>sign</code>.
+		 * @param certPathCerts    The certificates of the certification path.
+		 * @throws AnnotatedException if the certificate is revoked or the status cannot be checked
+		 *                            or some error occurs.
+		 */
+		protected static void CheckCrls(
+			PkixParameters			paramsPKIX,
+			X509Certificate			cert,
+			DateTime				validDate,
+			X509Certificate			sign,
+			AsymmetricKeyParameter	workingPublicKey,
+			IList					certPathCerts)
+		{
+			Exception lastException = null;
+			CrlDistPoint crldp = null;
+
+			try
+			{
+				crldp = CrlDistPoint.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.CrlDistributionPoints));
+			}
+			catch (Exception e)
+			{
+				throw new Exception("CRL distribution point extension could not be read.", e);
+			}
+
+			try
+			{
+				PkixCertPathValidatorUtilities.AddAdditionalStoresFromCrlDistributionPoint(crldp, paramsPKIX);
+			}
+			catch (Exception e)
+			{
+				throw new Exception(
+					"No additional CRL locations could be decoded from CRL distribution point extension.", e);
+			}
+			CertStatus certStatus = new CertStatus();
+			ReasonsMask reasonsMask = new ReasonsMask();
+
+			bool validCrlFound = false;
+
+			// for each distribution point
+			if (crldp != null)
+			{
+				DistributionPoint[] dps = null;
+				try
+				{
+					dps = crldp.GetDistributionPoints();
+				}
+				catch (Exception e)
+				{
+					throw new Exception("Distribution points could not be read.", e);
+				}
+				if (dps != null)
+				{
+					for (int i = 0; i < dps.Length && certStatus.Status == CertStatus.Unrevoked && !reasonsMask.IsAllReasons; i++)
+					{
+						PkixParameters paramsPKIXClone = (PkixParameters)paramsPKIX.Clone();
+						try
+						{
+							CheckCrl(dps[i], paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask, certPathCerts);
+							validCrlFound = true;
+						}
+						catch (Exception e)
+						{
+							lastException = e;
+						}
+					}
+				}
+			}
+
+			/*
+			 * If the revocation status has not been determined, repeat the process
+			 * above with any available CRLs not specified in a distribution point
+			 * but issued by the certificate issuer.
+			 */
+
+			if (certStatus.Status == CertStatus.Unrevoked && !reasonsMask.IsAllReasons)
+			{
+				try
+				{
+					/*
+					 * assume a DP with both the reasons and the cRLIssuer fields
+					 * omitted and a distribution point name of the certificate
+					 * issuer.
+					 */
+					Asn1Object issuer = null;
+					try
+					{
+						issuer = new Asn1InputStream(cert.IssuerDN.GetEncoded()).ReadObject();
+					}
+					catch (Exception e)
+					{
+						throw new Exception("Issuer from certificate for CRL could not be reencoded.", e);
+					}
+					DistributionPoint dp = new DistributionPoint(new DistributionPointName(0, new GeneralNames(
+						new GeneralName(GeneralName.DirectoryName, issuer))), null, null);
+					PkixParameters paramsPKIXClone = (PkixParameters)paramsPKIX.Clone();
+
+					CheckCrl(dp, paramsPKIXClone, cert, validDate, sign, workingPublicKey, certStatus, reasonsMask,
+						certPathCerts);
+
+					validCrlFound = true;
+				}
+				catch (Exception e)
+				{
+					lastException = e;
+				}
+			}
+
+			if (!validCrlFound)
+			{
+				throw lastException;
+			}
+			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;
+				message += ", reason: " + CrlReasons[certStatus.Status];
+				throw new Exception(message);
+			}
+
+			if (!reasonsMask.IsAllReasons && certStatus.Status == CertStatus.Unrevoked)
+			{
+				certStatus.Status = CertStatus.Undetermined;
+			}
+
+			if (certStatus.Status == CertStatus.Undetermined)
+			{
+				throw new Exception("Certificate status could not be determined.");
+			}
+		}
+
+		internal static PkixPolicyNode PrepareCertB(
+			PkixCertPath	certPath,
+			int				index,
+			IList[]			policyNodes,
+			PkixPolicyNode	validPolicyTree,
+			int				policyMapping)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+			int n = certs.Count;
+			// i as defined in the algorithm description
+			int i = n - index;
+			// (b)
+			//
+			Asn1Sequence pm = null;
+			try
+			{
+				pm = (Asn1Sequence)Asn1Sequence.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyMappings));
+			}
+			catch (Exception ex)
+			{
+				throw new PkixCertPathValidatorException(
+					"Policy mappings extension could not be decoded.", ex, certPath, index);
+			}
+			PkixPolicyNode _validPolicyTree = validPolicyTree;
+			if (pm != null)
+			{
+				Asn1Sequence mappings = (Asn1Sequence)pm;
+				IDictionary m_idp = Platform.CreateHashtable();
+				ISet s_idp = new HashSet();
+
+				for (int j = 0; j < mappings.Count; j++)
+				{
+					Asn1Sequence mapping = (Asn1Sequence) mappings[j];
+					string id_p = ((DerObjectIdentifier) mapping[0]).Id;
+					string sd_p = ((DerObjectIdentifier) mapping[1]).Id;
+					ISet tmp;
+
+					if (!m_idp.Contains(id_p))
+					{
+						tmp = new HashSet();
+						tmp.Add(sd_p);
+						m_idp[id_p] = tmp;
+						s_idp.Add(id_p);
+					}
+					else
+					{
+						tmp = (ISet)m_idp[id_p];
+						tmp.Add(sd_p);
+					}
+				}
+
+				IEnumerator it_idp = s_idp.GetEnumerator();
+				while (it_idp.MoveNext())
+				{
+					string id_p = (string)it_idp.Current;
+
+					//
+					// (1)
+					//
+					if (policyMapping > 0)
+					{
+						bool idp_found = false;
+						IEnumerator nodes_i = policyNodes[i].GetEnumerator();
+
+						while (nodes_i.MoveNext())
+						{
+							PkixPolicyNode node = (PkixPolicyNode)nodes_i.Current;
+							if (node.ValidPolicy.Equals(id_p))
+							{
+								idp_found = true;
+								node.ExpectedPolicies = (ISet)m_idp[id_p];
+								break;
+							}
+						}
+
+						if (!idp_found)
+						{
+							nodes_i = policyNodes[i].GetEnumerator();
+							while (nodes_i.MoveNext())
+							{
+								PkixPolicyNode node = (PkixPolicyNode)nodes_i.Current;
+								if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(node.ValidPolicy))
+								{
+									ISet pq = null;
+									Asn1Sequence policies = null;
+									try
+									{
+										policies = (Asn1Sequence)PkixCertPathValidatorUtilities.GetExtensionValue(cert,
+											X509Extensions.CertificatePolicies);
+									}
+									catch (Exception e)
+									{
+										throw new PkixCertPathValidatorException(
+											"Certificate policies extension could not be decoded.", e, certPath, index);
+									}
+
+									foreach (Asn1Encodable ae in policies)
+									{
+										PolicyInformation pinfo = null;
+										try
+										{
+											pinfo = PolicyInformation.GetInstance(ae.ToAsn1Object());
+										}
+										catch (Exception ex)
+										{
+											throw new PkixCertPathValidatorException(
+												"Policy information could not be decoded.", ex, certPath, index);
+										}
+										if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(pinfo.PolicyIdentifier.Id))
+										{
+											try
+											{
+												pq = PkixCertPathValidatorUtilities
+													.GetQualifierSet(pinfo.PolicyQualifiers);
+											}
+											catch (PkixCertPathValidatorException ex)
+											{
+												throw new PkixCertPathValidatorException(
+													"Policy qualifier info set could not be decoded.", ex, certPath,
+													index);
+											}
+											break;
+										}
+									}
+									bool ci = false;
+									ISet critExtOids = cert.GetCriticalExtensionOids();
+									if (critExtOids != null)
+									{
+										ci = critExtOids.Contains(X509Extensions.CertificatePolicies.Id);
+									}
+
+									PkixPolicyNode p_node = (PkixPolicyNode)node.Parent;
+									if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(p_node.ValidPolicy))
+									{
+										PkixPolicyNode c_node = new PkixPolicyNode(Platform.CreateArrayList(), i,
+											(ISet)m_idp[id_p], p_node, pq, id_p, ci);
+										p_node.AddChild(c_node);
+										policyNodes[i].Add(c_node);
+									}
+									break;
+								}
+							}
+						}
+
+						//
+						// (2)
+						//
+					}
+					else if (policyMapping <= 0)
+					{
+                        foreach (PkixPolicyNode node in Platform.CreateArrayList(policyNodes[i]))
+                        {
+							if (node.ValidPolicy.Equals(id_p))
+							{
+								node.Parent.RemoveChild(node);
+
+                                for (int k = i - 1; k >= 0; k--)
+								{
+                                    foreach (PkixPolicyNode node2 in Platform.CreateArrayList(policyNodes[k]))
+									{
+										if (!node2.HasChildren)
+										{
+											_validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(
+												_validPolicyTree, policyNodes, node2);
+
+                                            if (_validPolicyTree == null)
+												break;
+										}
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+			return _validPolicyTree;
+		}
+
+		internal static ISet[] ProcessCrlA1ii(
+			DateTime		currentDate,
+			PkixParameters	paramsPKIX,
+			X509Certificate	cert,
+			X509Crl			crl)
+		{
+			ISet deltaSet = new HashSet();
+			X509CrlStoreSelector crlselect = new X509CrlStoreSelector();
+			crlselect.CertificateChecking = cert;
+
+			try
+			{
+				IList issuer = Platform.CreateArrayList();
+				issuer.Add(crl.IssuerDN);
+				crlselect.Issuers = issuer;
+			}
+			catch (IOException e)
+			{
+				throw new Exception("Cannot extract issuer from CRL." + e, e);
+			}
+
+			crlselect.CompleteCrlEnabled = true;
+			ISet completeSet = CrlUtilities.FindCrls(crlselect, paramsPKIX, currentDate);
+
+			if (paramsPKIX.IsUseDeltasEnabled)
+			{
+				// get delta CRL(s)
+				try
+				{
+					deltaSet.AddAll(PkixCertPathValidatorUtilities.GetDeltaCrls(currentDate, paramsPKIX, crl));
+				}
+				catch (Exception e)
+				{
+					throw new Exception("Exception obtaining delta CRLs.", e);
+				}
+			}
+
+			return new ISet[]{ completeSet, deltaSet };
+		}
+
+		internal static ISet ProcessCrlA1i(
+			DateTime		currentDate,
+			PkixParameters	paramsPKIX,
+			X509Certificate	cert,
+			X509Crl			crl)
+		{
+			ISet deltaSet = new HashSet();
+			if (paramsPKIX.IsUseDeltasEnabled)
+			{
+				CrlDistPoint freshestCRL = null;
+				try
+				{
+					freshestCRL = CrlDistPoint.GetInstance(
+						PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.FreshestCrl));
+				}
+				catch (Exception e)
+				{
+					throw new Exception("Freshest CRL extension could not be decoded from certificate.", e);
+				}
+
+				if (freshestCRL == null)
+				{
+					try
+					{
+						freshestCRL = CrlDistPoint.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(crl, X509Extensions.FreshestCrl));
+					}
+					catch (Exception e)
+					{
+						throw new Exception("Freshest CRL extension could not be decoded from CRL.", e);
+					}
+				}
+				if (freshestCRL != null)
+				{
+					try
+					{
+						PkixCertPathValidatorUtilities.AddAdditionalStoresFromCrlDistributionPoint(freshestCRL, paramsPKIX);
+					}
+					catch (Exception e)
+					{
+						throw new Exception(
+							"No new delta CRL locations could be added from Freshest CRL extension.", e);
+					}
+					// get delta CRL(s)
+					try
+					{
+						deltaSet.AddAll(PkixCertPathValidatorUtilities.GetDeltaCrls(currentDate, paramsPKIX, crl));
+					}
+					catch (Exception e)
+					{
+						throw new Exception("Exception obtaining delta CRLs.", e);
+					}
+				}
+			}
+			return deltaSet;
+		}
+
+		internal static void ProcessCertF(
+			PkixCertPath	certPath,
+			int				index,
+			PkixPolicyNode	validPolicyTree,
+			int				explicitPolicy)
+		{
+			//
+			// (f)
+			//
+			if (explicitPolicy <= 0 && validPolicyTree == null)
+			{
+				throw new PkixCertPathValidatorException(
+					"No valid policy tree found when one expected.", null, certPath, index);
+			}
+		}
+
+		internal static void ProcessCertA(
+			PkixCertPath			certPath,
+			PkixParameters			paramsPKIX,
+			int						index,
+			AsymmetricKeyParameter	workingPublicKey,
+			X509Name				workingIssuerName,
+			X509Certificate			sign)
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+			//
+			// (a) verify
+			//
+			try
+			{
+				// (a) (1)
+				//
+				cert.Verify(workingPublicKey);
+			}
+			catch (GeneralSecurityException e)
+			{
+				throw new PkixCertPathValidatorException("Could not validate certificate signature.", e, certPath, index);
+			}
+
+			try
+			{
+				// (a) (2)
+				//
+				cert.CheckValidity(PkixCertPathValidatorUtilities
+					.GetValidCertDateFromValidityModel(paramsPKIX, certPath, index));
+			}
+			catch (CertificateExpiredException e)
+			{
+				throw new PkixCertPathValidatorException("Could not validate certificate: " + e.Message, e, certPath, index);
+			}
+			catch (CertificateNotYetValidException e)
+			{
+				throw new PkixCertPathValidatorException("Could not validate certificate: " + e.Message, e, certPath, index);
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathValidatorException("Could not validate time of certificate.", e, certPath, index);
+			}
+
+			//
+			// (a) (3)
+			//
+			if (paramsPKIX.IsRevocationEnabled)
+			{
+				try
+				{
+					CheckCrls(paramsPKIX, cert, PkixCertPathValidatorUtilities.GetValidCertDateFromValidityModel(paramsPKIX,
+						certPath, index), sign, workingPublicKey, certs);
+				}
+				catch (Exception e)
+				{
+					Exception cause = e.InnerException;
+					if (cause == null)
+					{
+						cause = e;
+					}
+					throw new PkixCertPathValidatorException(e.Message, cause, certPath, index);
+				}
+			}
+
+			//
+			// (a) (4) name chaining
+			//
+			X509Name issuer = PkixCertPathValidatorUtilities.GetIssuerPrincipal(cert);
+			if (!issuer.Equivalent(workingIssuerName, true))
+			{
+				throw new PkixCertPathValidatorException("IssuerName(" + issuer
+					+ ") does not match SubjectName(" + workingIssuerName + ") of signing certificate.", null,
+					certPath, index);
+			}
+		}
+
+		internal static int PrepareNextCertI1(
+			PkixCertPath	certPath,
+			int				index,
+			int				explicitPolicy)
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+			//
+			// (i)
+			//
+			Asn1Sequence pc = null;
+			try
+			{
+				pc = DerSequence.GetInstance(
+					PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyConstraints));
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathValidatorException(
+					"Policy constraints extension cannot be decoded.", e, certPath, index);
+			}
+
+			int tmpInt;
+
+			if (pc != null)
+			{
+				IEnumerator policyConstraints = pc.GetEnumerator();
+
+				while (policyConstraints.MoveNext())
+				{
+					try
+					{
+						Asn1TaggedObject constraint = Asn1TaggedObject.GetInstance(policyConstraints.Current);
+						if (constraint.TagNo == 0)
+						{
+							tmpInt = DerInteger.GetInstance(constraint, false).Value.IntValue;
+							if (tmpInt < explicitPolicy)
+							{
+								return tmpInt;
+							}
+							break;
+						}
+					}
+					catch (ArgumentException e)
+					{
+						throw new PkixCertPathValidatorException(
+							"Policy constraints extension contents cannot be decoded.", e, certPath, index);
+					}
+				}
+			}
+			return explicitPolicy;
+		}
+
+		internal static int PrepareNextCertI2(
+			PkixCertPath	certPath,
+			int				index,
+			int				policyMapping)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+
+			//
+			// (i)
+			//
+			Asn1Sequence pc = null;
+			try
+			{
+				pc = DerSequence.GetInstance(
+					PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyConstraints));
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathValidatorException(
+					"Policy constraints extension cannot be decoded.", e, certPath, index);
+			}
+
+			int tmpInt;
+
+			if (pc != null)
+			{
+				IEnumerator policyConstraints = pc.GetEnumerator();
+
+				while (policyConstraints.MoveNext())
+				{
+					try
+					{
+						Asn1TaggedObject constraint = Asn1TaggedObject.GetInstance(policyConstraints.Current);
+						if (constraint.TagNo == 1)
+						{
+							tmpInt = DerInteger.GetInstance(constraint, false).Value.IntValue;
+							if (tmpInt < policyMapping)
+							{
+								return tmpInt;
+							}
+							break;
+						}
+					}
+					catch (ArgumentException e)
+					{
+						throw new PkixCertPathValidatorException(
+							"Policy constraints extension contents cannot be decoded.", e, certPath, index);
+					}
+				}
+			}
+			return policyMapping;
+		}
+
+		internal static void PrepareNextCertG(
+			PkixCertPath				certPath,
+			int							index,
+			PkixNameConstraintValidator	nameConstraintValidator)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+
+			//
+			// (g) handle the name constraints extension
+			//
+			NameConstraints nc = null;
+			try
+			{
+				Asn1Sequence ncSeq = DerSequence.GetInstance(
+					PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.NameConstraints));
+				if (ncSeq != null)
+				{
+					nc = new NameConstraints(ncSeq);
+				}
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathValidatorException(
+					"Name constraints extension could not be decoded.", e, certPath, index);
+			}
+			if (nc != null)
+			{
+				//
+				// (g) (1) permitted subtrees
+				//
+				Asn1Sequence permitted = nc.PermittedSubtrees;
+				if (permitted != null)
+				{
+					try
+					{
+						nameConstraintValidator.IntersectPermittedSubtree(permitted);
+					}
+					catch (Exception ex)
+					{
+						throw new PkixCertPathValidatorException(
+							"Permitted subtrees cannot be build from name constraints extension.", ex, certPath, index);
+					}
+				}
+
+				//
+				// (g) (2) excluded subtrees
+				//
+				Asn1Sequence excluded = nc.ExcludedSubtrees;
+				if (excluded != null)
+				{
+					IEnumerator e = excluded.GetEnumerator();
+					try
+					{
+						while (e.MoveNext())
+						{
+							GeneralSubtree subtree = GeneralSubtree.GetInstance(e.Current);
+							nameConstraintValidator.AddExcludedSubtree(subtree);
+						}
+					}
+					catch (Exception ex)
+					{
+						throw new PkixCertPathValidatorException(
+							"Excluded subtrees cannot be build from name constraints extension.", ex, certPath, index);
+					}
+				}
+			}
+		}
+
+		internal static int PrepareNextCertJ(
+			PkixCertPath	certPath,
+			int				index,
+			int				inhibitAnyPolicy)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+
+			//
+			// (j)
+			//
+			DerInteger iap = null;
+			try
+			{
+				iap = DerInteger.GetInstance(
+					PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.InhibitAnyPolicy));
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathValidatorException(
+					"Inhibit any-policy extension cannot be decoded.", e, certPath, index);
+			}
+
+			if (iap != null)
+			{
+				int _inhibitAnyPolicy = iap.Value.IntValue;
+
+				if (_inhibitAnyPolicy < inhibitAnyPolicy)
+					return _inhibitAnyPolicy;
+			}
+			return inhibitAnyPolicy;
+		}
+
+		internal static void PrepareNextCertK(
+			PkixCertPath	certPath,
+			int				index)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+			//
+			// (k)
+			//
+			BasicConstraints bc = null;
+			try
+			{
+				bc = BasicConstraints.GetInstance(
+					PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.BasicConstraints));
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+					index);
+			}
+			if (bc != null)
+			{
+				if (!(bc.IsCA()))
+					throw new PkixCertPathValidatorException("Not a CA certificate");
+			}
+			else
+			{
+				throw new PkixCertPathValidatorException("Intermediate certificate lacks BasicConstraints");
+			}
+		}
+
+		internal static int PrepareNextCertL(
+			PkixCertPath	certPath,
+			int				index,
+			int				maxPathLength)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+			//
+			// (l)
+			//
+			if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert))
+			{
+				if (maxPathLength <= 0)
+				{
+					throw new PkixCertPathValidatorException("Max path length not greater than zero", null, certPath, index);
+				}
+
+				return maxPathLength - 1;
+			}
+			return maxPathLength;
+		}
+
+		internal static int PrepareNextCertM(
+			PkixCertPath	certPath,
+			int				index,
+			int				maxPathLength)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+
+			//
+			// (m)
+			//
+			BasicConstraints bc = null;
+			try
+			{
+				bc = BasicConstraints.GetInstance(
+					PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.BasicConstraints));
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathValidatorException("Basic constraints extension cannot be decoded.", e, certPath,
+					index);
+			}
+			if (bc != null)
+			{
+				BigInteger _pathLengthConstraint = bc.PathLenConstraint;
+
+				if (_pathLengthConstraint != null)
+				{
+					int _plc = _pathLengthConstraint.IntValue;
+
+					if (_plc < maxPathLength)
+					{
+						return _plc;
+					}
+				}
+			}
+			return maxPathLength;
+		}
+
+		internal static void PrepareNextCertN(
+			PkixCertPath	certPath,
+			int				index)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+
+			//
+			// (n)
+			//
+			bool[] _usage = cert.GetKeyUsage();
+
+			if ((_usage != null) && !_usage[Rfc3280CertPathUtilities.KEY_CERT_SIGN])
+			{
+				throw new PkixCertPathValidatorException(
+					"Issuer certificate keyusage extension is critical and does not permit key signing.", null,
+					certPath, index);
+			}
+		}
+
+		internal static void PrepareNextCertO(
+			PkixCertPath	certPath,
+			int				index,
+			ISet			criticalExtensions,
+			IList			pathCheckers)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+
+			//
+			// (o)
+			//
+			IEnumerator tmpIter = pathCheckers.GetEnumerator();
+			while (tmpIter.MoveNext())
+			{
+				try
+				{
+					((PkixCertPathChecker)tmpIter.Current).Check(cert, criticalExtensions);
+				}
+				catch (PkixCertPathValidatorException e)
+				{
+					throw new PkixCertPathValidatorException(e.Message, e.InnerException, certPath, index);
+				}
+			}
+			if (!criticalExtensions.IsEmpty)
+			{
+				throw new PkixCertPathValidatorException("Certificate has unsupported critical extension.", null, certPath,
+					index);
+			}
+		}
+
+		internal static int PrepareNextCertH1(
+			PkixCertPath	certPath,
+			int				index,
+			int				explicitPolicy)
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+
+			//
+			// (h)
+			//
+			if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert))
+			{
+				//
+				// (1)
+				//
+				if (explicitPolicy != 0)
+					return explicitPolicy - 1;
+			}
+			return explicitPolicy;
+		}
+
+		internal static int PrepareNextCertH2(
+			PkixCertPath	certPath,
+			int				index,
+			int				policyMapping)
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+
+			//
+			// (h)
+			//
+			if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert))
+			{
+				//
+				// (2)
+				//
+				if (policyMapping != 0)
+					return policyMapping - 1;
+			}
+			return policyMapping;
+		}
+
+
+		internal static int PrepareNextCertH3(
+			PkixCertPath	certPath,
+			int				index,
+			int				inhibitAnyPolicy)
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+
+			//
+			// (h)
+			//
+			if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert))
+			{
+				//
+				// (3)
+				//
+				if (inhibitAnyPolicy != 0)
+					return inhibitAnyPolicy - 1;
+			}
+			return inhibitAnyPolicy;
+		}
+
+		internal static int WrapupCertA(
+			int				explicitPolicy,
+			X509Certificate	cert)
+		{
+			//
+			// (a)
+			//
+			if (!PkixCertPathValidatorUtilities.IsSelfIssued(cert) && (explicitPolicy != 0))
+			{
+				explicitPolicy--;
+			}
+			return explicitPolicy;
+		}
+
+		internal static int WrapupCertB(
+			PkixCertPath	certPath,
+			int				index,
+			int				explicitPolicy)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+
+			//
+			// (b)
+			//
+			int tmpInt;
+			Asn1Sequence pc = null;
+			try
+			{
+				pc = DerSequence.GetInstance(
+					PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.PolicyConstraints));
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathValidatorException("Policy constraints could not be decoded.", e, certPath, index);
+			}
+
+			if (pc != null)
+			{
+				IEnumerator policyConstraints = pc.GetEnumerator();
+
+				while (policyConstraints.MoveNext())
+				{
+					Asn1TaggedObject constraint = (Asn1TaggedObject)policyConstraints.Current;
+					switch (constraint.TagNo)
+					{
+						case 0:
+							try
+							{
+								tmpInt = DerInteger.GetInstance(constraint, false).Value.IntValue;
+							}
+							catch (Exception e)
+							{
+								throw new PkixCertPathValidatorException(
+									"Policy constraints requireExplicitPolicy field could not be decoded.", e, certPath,
+									index);
+							}
+							if (tmpInt == 0)
+							{
+								return 0;
+							}
+							break;
+					}
+				}
+			}
+			return explicitPolicy;
+		}
+
+		internal static void WrapupCertF(
+			PkixCertPath	certPath,
+			int				index,
+			IList			pathCheckers,
+			ISet			criticalExtensions)
+			//throws CertPathValidatorException
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+			IEnumerator tmpIter = pathCheckers.GetEnumerator();
+
+			while (tmpIter.MoveNext())
+			{
+				try
+				{
+					((PkixCertPathChecker)tmpIter.Current).Check(cert, criticalExtensions);
+				}
+				catch (PkixCertPathValidatorException e)
+				{
+					throw new PkixCertPathValidatorException("Additional certificate path checker failed.", e, certPath,
+						index);
+				}
+			}
+
+			if (!criticalExtensions.IsEmpty)
+			{
+				throw new PkixCertPathValidatorException("Certificate has unsupported critical extension",
+					null, certPath, index);
+			}
+		}
+
+		internal static PkixPolicyNode WrapupCertG(
+			PkixCertPath	certPath,
+			PkixParameters	paramsPKIX,
+			ISet			userInitialPolicySet,
+			int				index,
+			IList[]			policyNodes,
+			PkixPolicyNode	validPolicyTree,
+			ISet			acceptablePolicies)
+		{
+			int n = certPath.Certificates.Count;
+
+			//
+			// (g)
+			//
+			PkixPolicyNode intersection;
+
+			//
+			// (g) (i)
+			//
+			if (validPolicyTree == null)
+			{
+				if (paramsPKIX.IsExplicitPolicyRequired)
+				{
+					throw new PkixCertPathValidatorException(
+						"Explicit policy requested but none available.", null, certPath, index);
+				}
+				intersection = null;
+			}
+			else if (PkixCertPathValidatorUtilities.IsAnyPolicy(userInitialPolicySet)) // (g)
+				// (ii)
+			{
+				if (paramsPKIX.IsExplicitPolicyRequired)
+				{
+					if (acceptablePolicies.IsEmpty)
+					{
+						throw new PkixCertPathValidatorException(
+							"Explicit policy requested but none available.", null, certPath, index);
+					}
+					else
+					{
+						ISet _validPolicyNodeSet = new HashSet();
+
+						for (int j = 0; j < policyNodes.Length; j++)
+						{
+							IList _nodeDepth = policyNodes[j];
+
+							for (int k = 0; k < _nodeDepth.Count; k++)
+							{
+								PkixPolicyNode _node = (PkixPolicyNode)_nodeDepth[k];
+
+								if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(_node.ValidPolicy))
+								{
+									foreach (object o in _node.Children)
+									{
+										_validPolicyNodeSet.Add(o);
+									}
+								}
+							}
+						}
+
+						foreach (PkixPolicyNode _node in _validPolicyNodeSet)
+						{
+							string _validPolicy = _node.ValidPolicy;
+
+							if (!acceptablePolicies.Contains(_validPolicy))
+							{
+								// TODO?
+								// validPolicyTree =
+								// removePolicyNode(validPolicyTree, policyNodes,
+								// _node);
+							}
+						}
+						if (validPolicyTree != null)
+						{
+							for (int j = (n - 1); j >= 0; j--)
+							{
+								IList nodes = policyNodes[j];
+
+								for (int k = 0; k < nodes.Count; k++)
+								{
+									PkixPolicyNode node = (PkixPolicyNode)nodes[k];
+									if (!node.HasChildren)
+									{
+										validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(validPolicyTree,
+											policyNodes, node);
+									}
+								}
+							}
+						}
+					}
+				}
+
+				intersection = validPolicyTree;
+			}
+			else
+			{
+				//
+				// (g) (iii)
+				//
+				// This implementation is not exactly same as the one described in
+				// RFC3280.
+				// However, as far as the validation result is concerned, both
+				// produce
+				// adequate result. The only difference is whether AnyPolicy is
+				// remain
+				// in the policy tree or not.
+				//
+				// (g) (iii) 1
+				//
+				ISet _validPolicyNodeSet = new HashSet();
+
+				for (int j = 0; j < policyNodes.Length; j++)
+				{
+					IList _nodeDepth = policyNodes[j];
+
+					for (int k = 0; k < _nodeDepth.Count; k++)
+					{
+						PkixPolicyNode _node = (PkixPolicyNode)_nodeDepth[k];
+
+						if (Rfc3280CertPathUtilities.ANY_POLICY.Equals(_node.ValidPolicy))
+						{
+							foreach (PkixPolicyNode _c_node in _node.Children)
+							{
+								if (!Rfc3280CertPathUtilities.ANY_POLICY.Equals(_c_node.ValidPolicy))
+								{
+									_validPolicyNodeSet.Add(_c_node);
+								}
+							}
+						}
+					}
+				}
+
+				//
+				// (g) (iii) 2
+				//
+				IEnumerator _vpnsIter = _validPolicyNodeSet.GetEnumerator();
+				while (_vpnsIter.MoveNext())
+				{
+					PkixPolicyNode _node = (PkixPolicyNode)_vpnsIter.Current;
+					string _validPolicy = _node.ValidPolicy;
+
+					if (!userInitialPolicySet.Contains(_validPolicy))
+					{
+						validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(validPolicyTree, policyNodes, _node);
+					}
+				}
+
+				//
+				// (g) (iii) 4
+				//
+				if (validPolicyTree != null)
+				{
+					for (int j = (n - 1); j >= 0; j--)
+					{
+						IList nodes = policyNodes[j];
+
+						for (int k = 0; k < nodes.Count; k++)
+						{
+							PkixPolicyNode node = (PkixPolicyNode)nodes[k];
+							if (!node.HasChildren)
+							{
+								validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(validPolicyTree, policyNodes,
+									node);
+							}
+						}
+					}
+				}
+
+				intersection = validPolicyTree;
+			}
+			return intersection;
+		}
+
+		/**
+		* If use-deltas is set, verify the issuer and scope of the delta CRL.
+		*
+		* @param deltaCRL    The delta CRL.
+		* @param completeCRL The complete CRL.
+		* @param pkixParams  The PKIX paramaters.
+		* @throws AnnotatedException if an exception occurs.
+		*/
+		internal static void ProcessCrlC(
+			X509Crl			deltaCRL,
+			X509Crl			completeCRL,
+			PkixParameters	pkixParams)
+		{
+			if (deltaCRL == null)
+				return;
+
+			IssuingDistributionPoint completeidp = null;
+			try
+			{
+				completeidp = IssuingDistributionPoint.GetInstance(
+					PkixCertPathValidatorUtilities.GetExtensionValue(completeCRL, X509Extensions.IssuingDistributionPoint));
+			}
+			catch (Exception e)
+			{
+				throw new Exception("000 Issuing distribution point extension could not be decoded.", e);
+			}
+
+			if (pkixParams.IsUseDeltasEnabled)
+			{
+				// (c) (1)
+				if (!deltaCRL.IssuerDN.Equivalent(completeCRL.IssuerDN, true))
+					throw new Exception("Complete CRL issuer does not match delta CRL issuer.");
+
+				// (c) (2)
+				IssuingDistributionPoint deltaidp = null;
+				try
+				{
+					deltaidp = IssuingDistributionPoint.GetInstance(
+						PkixCertPathValidatorUtilities.GetExtensionValue(deltaCRL, X509Extensions.IssuingDistributionPoint));
+				}
+				catch (Exception e)
+				{
+					throw new Exception(
+						"Issuing distribution point extension from delta CRL could not be decoded.", e);
+				}
+
+				if (!Platform.Equals(completeidp, deltaidp))
+				{
+					throw new Exception(
+						"Issuing distribution point extension from delta CRL and complete CRL does not match.");
+				}
+
+				// (c) (3)
+				Asn1Object completeKeyIdentifier = null;
+				try
+				{
+					completeKeyIdentifier = PkixCertPathValidatorUtilities.GetExtensionValue(
+						completeCRL, X509Extensions.AuthorityKeyIdentifier);
+				}
+				catch (Exception e)
+				{
+					throw new Exception(
+						"Authority key identifier extension could not be extracted from complete CRL.", e);
+				}
+
+				Asn1Object deltaKeyIdentifier = null;
+				try
+				{
+					deltaKeyIdentifier = PkixCertPathValidatorUtilities.GetExtensionValue(
+						deltaCRL, X509Extensions.AuthorityKeyIdentifier);
+				}
+				catch (Exception e)
+				{
+					throw new Exception(
+						"Authority key identifier extension could not be extracted from delta CRL.", e);
+				}
+
+				if (completeKeyIdentifier == null)
+					throw new Exception("CRL authority key identifier is null.");
+
+				if (deltaKeyIdentifier == null)
+					throw new Exception("Delta CRL authority key identifier is null.");
+
+				if (!completeKeyIdentifier.Equals(deltaKeyIdentifier))
+				{
+					throw new Exception(
+						"Delta CRL authority key identifier does not match complete CRL authority key identifier.");
+				}
+			}
+		}
+
+		internal static void ProcessCrlI(
+			DateTime		validDate,
+			X509Crl			deltacrl,
+			object			cert,
+			CertStatus		certStatus,
+			PkixParameters	pkixParams)
+		{
+			if (pkixParams.IsUseDeltasEnabled && deltacrl != null)
+			{
+				PkixCertPathValidatorUtilities.GetCertStatus(validDate, deltacrl, cert, certStatus);
+			}
+		}
+
+		internal static void ProcessCrlJ(
+			DateTime	validDate,
+			X509Crl		completecrl,
+			object		cert,
+			CertStatus	certStatus)
+		{
+			if (certStatus.Status == CertStatus.Unrevoked)
+			{
+				PkixCertPathValidatorUtilities.GetCertStatus(validDate, completecrl, cert, certStatus);
+			}
+		}
+
+		internal static PkixPolicyNode ProcessCertE(
+			PkixCertPath	certPath,
+			int				index,
+			PkixPolicyNode	validPolicyTree)
+		{
+			IList certs = certPath.Certificates;
+			X509Certificate cert = (X509Certificate)certs[index];
+
+			//
+			// (e)
+			//
+			Asn1Sequence certPolicies = null;
+			try
+			{
+				certPolicies = DerSequence.GetInstance(
+					PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.CertificatePolicies));
+			}
+			catch (Exception e)
+			{
+				throw new PkixCertPathValidatorException("Could not read certificate policies extension from certificate.",
+					e, certPath, index);
+			}
+			if (certPolicies == null)
+			{
+				validPolicyTree = null;
+			}
+			return validPolicyTree;
+		}
+
+		internal static readonly string[] CrlReasons = new string[]
+		{
+			"unspecified",
+			"keyCompromise",
+			"cACompromise",
+			"affiliationChanged",
+			"superseded",
+			"cessationOfOperation",
+			"certificateHold",
+			"unknown",
+			"removeFromCRL",
+			"privilegeWithdrawn",
+			"aACompromise"
+		};
+	}
+}
diff --git a/Crypto/src/pkix/Rfc3281CertPathUtilities.cs b/Crypto/src/pkix/Rfc3281CertPathUtilities.cs
new file mode 100644
index 000000000..bda2aa737
--- /dev/null
+++ b/Crypto/src/pkix/Rfc3281CertPathUtilities.cs
@@ -0,0 +1,608 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.X509.Store;
+
+namespace Org.BouncyCastle.Pkix
+{
+	internal class Rfc3281CertPathUtilities
+	{
+		internal static void ProcessAttrCert7(
+			IX509AttributeCertificate	attrCert,
+			PkixCertPath				certPath,
+			PkixCertPath				holderCertPath,
+			PkixParameters				pkixParams)
+		{
+			// TODO:
+			// AA Controls
+			// Attribute encryption
+			// Proxy
+			ISet critExtOids = attrCert.GetCriticalExtensionOids();
+
+			// 7.1
+			// process extensions
+
+			// target information checked in step 6 / X509AttributeCertStoreSelector
+			if (critExtOids.Contains(X509Extensions.TargetInformation.Id))
+			{
+				try
+				{
+					TargetInformation.GetInstance(PkixCertPathValidatorUtilities
+						.GetExtensionValue(attrCert, X509Extensions.TargetInformation));
+				}
+				catch (Exception e)
+				{
+					throw new PkixCertPathValidatorException(
+						"Target information extension could not be read.", e);
+				}
+			}
+			critExtOids.Remove(X509Extensions.TargetInformation.Id);
+			foreach (PkixAttrCertChecker checker in pkixParams.GetAttrCertCheckers())
+			{
+				checker.Check(attrCert, certPath, holderCertPath, critExtOids);
+			}
+			if (!critExtOids.IsEmpty)
+			{
+				throw new PkixCertPathValidatorException(
+					"Attribute certificate contains unsupported critical extensions: "
+						+ critExtOids);
+			}
+		}
+
+		/**
+		* Checks if an attribute certificate is revoked.
+		* 
+		* @param attrCert Attribute certificate to check if it is revoked.
+		* @param paramsPKIX PKIX parameters.
+		* @param issuerCert The issuer certificate of the attribute certificate
+		*            <code>attrCert</code>.
+		* @param validDate The date when the certificate revocation status should
+		*            be checked.
+		* @param certPathCerts The certificates of the certification path to be
+		*            checked.
+		* 
+		* @throws CertPathValidatorException if the certificate is revoked or the
+		*             status cannot be checked or some error occurs.
+		*/
+		internal static void CheckCrls(
+			IX509AttributeCertificate	attrCert,
+			PkixParameters				paramsPKIX,
+			X509Certificate				issuerCert,
+			DateTime					validDate,
+			IList						certPathCerts)
+		{
+			if (paramsPKIX.IsRevocationEnabled)
+			{
+				// check if revocation is available
+				if (attrCert.GetExtensionValue(X509Extensions.NoRevAvail) == null)
+				{
+					CrlDistPoint crldp = null;
+					try
+					{
+						crldp = CrlDistPoint.GetInstance(
+							PkixCertPathValidatorUtilities.GetExtensionValue(
+								attrCert, X509Extensions.CrlDistributionPoints));
+					}
+					catch (Exception e)
+					{
+						throw new PkixCertPathValidatorException(
+							"CRL distribution point extension could not be read.", e);
+					}
+					try
+					{
+						PkixCertPathValidatorUtilities
+							.AddAdditionalStoresFromCrlDistributionPoint(crldp, paramsPKIX);
+					}
+					catch (Exception e)
+					{
+						throw new PkixCertPathValidatorException(
+							"No additional CRL locations could be decoded from CRL distribution point extension.", e);
+					}
+					CertStatus certStatus = new CertStatus();
+					ReasonsMask reasonsMask = new ReasonsMask();
+
+					Exception lastException = null;
+					bool validCrlFound = false;
+					// for each distribution point
+					if (crldp != null)
+					{
+						DistributionPoint[] dps = null;
+						try
+						{
+							dps = crldp.GetDistributionPoints();
+						}
+						catch (Exception e)
+						{
+							throw new PkixCertPathValidatorException(
+								"Distribution points could not be read.", e);
+						}
+						try
+						{
+							for (int i = 0; i < dps.Length
+								&& certStatus.Status == CertStatus.Unrevoked
+								&& !reasonsMask.IsAllReasons; i++)
+							{
+								PkixParameters paramsPKIXClone = (PkixParameters) paramsPKIX
+									.Clone();
+								CheckCrl(dps[i], attrCert, paramsPKIXClone,
+									validDate, issuerCert, certStatus, reasonsMask,
+									certPathCerts);
+								validCrlFound = true;
+							}
+						}
+						catch (Exception e)
+						{
+							lastException = new Exception(
+								"No valid CRL for distribution point found.", e);
+						}
+					}
+
+					/*
+					* If the revocation status has not been determined, repeat the
+					* process above with any available CRLs not specified in a
+					* distribution point but issued by the certificate issuer.
+					*/
+
+					if (certStatus.Status == CertStatus.Unrevoked
+						&& !reasonsMask.IsAllReasons)
+					{
+						try
+						{
+							/*
+							* assume a DP with both the reasons and the cRLIssuer
+							* fields omitted and a distribution point name of the
+							* certificate issuer.
+							*/
+							Asn1Object issuer = null;
+							try
+							{
+								issuer = new Asn1InputStream(
+									attrCert.Issuer.GetPrincipals()[0].GetEncoded()).ReadObject();
+							}
+							catch (Exception e)
+							{
+								throw new Exception(
+									"Issuer from certificate for CRL could not be reencoded.",
+									e);
+							}
+							DistributionPoint dp = new DistributionPoint(
+								new DistributionPointName(0, new GeneralNames(
+									new GeneralName(GeneralName.DirectoryName, issuer))), null, null);
+							PkixParameters paramsPKIXClone = (PkixParameters) paramsPKIX.Clone();
+							CheckCrl(dp, attrCert, paramsPKIXClone, validDate,
+								issuerCert, certStatus, reasonsMask, certPathCerts);
+							validCrlFound = true;
+						}
+						catch (Exception e)
+						{
+							lastException = new Exception(
+								"No valid CRL for distribution point found.", e);
+						}
+					}
+
+					if (!validCrlFound)
+					{
+						throw new PkixCertPathValidatorException(
+							"No valid CRL found.", lastException);
+					}
+					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 "
+							+ formattedDate;
+						message += ", reason: "
+							+ Rfc3280CertPathUtilities.CrlReasons[certStatus.Status];
+						throw new PkixCertPathValidatorException(message);
+					}
+					if (!reasonsMask.IsAllReasons
+						&& certStatus.Status == CertStatus.Unrevoked)
+					{
+						certStatus.Status = CertStatus.Undetermined;
+					}
+					if (certStatus.Status == CertStatus.Undetermined)
+					{
+						throw new PkixCertPathValidatorException(
+							"Attribute certificate status could not be determined.");
+					}
+
+				}
+				else
+				{
+					if (attrCert.GetExtensionValue(X509Extensions.CrlDistributionPoints) != null
+						|| attrCert.GetExtensionValue(X509Extensions.AuthorityInfoAccess) != null)
+					{
+						throw new PkixCertPathValidatorException(
+							"No rev avail extension is set, but also an AC revocation pointer.");
+					}
+				}
+			}
+		}
+
+		internal static void AdditionalChecks(
+			IX509AttributeCertificate	attrCert,
+			PkixParameters				pkixParams)
+		{
+			// 1
+			foreach (string oid in pkixParams.GetProhibitedACAttributes())
+			{
+				if (attrCert.GetAttributes(oid) != null)
+				{
+					throw new PkixCertPathValidatorException(
+						"Attribute certificate contains prohibited attribute: "
+							+ oid + ".");
+				}
+			}
+			foreach (string oid in pkixParams.GetNecessaryACAttributes())
+			{
+				if (attrCert.GetAttributes(oid) == null)
+				{
+					throw new PkixCertPathValidatorException(
+						"Attribute certificate does not contain necessary attribute: "
+							+ oid + ".");
+				}
+			}
+		}
+
+		internal static void ProcessAttrCert5(
+			IX509AttributeCertificate	attrCert,
+			PkixParameters				pkixParams)
+		{
+			try
+			{
+				attrCert.CheckValidity(PkixCertPathValidatorUtilities.GetValidDate(pkixParams));
+			}
+			catch (CertificateExpiredException e)
+			{
+				throw new PkixCertPathValidatorException(
+					"Attribute certificate is not valid.", e);
+			}
+			catch (CertificateNotYetValidException e)
+			{
+				throw new PkixCertPathValidatorException(
+					"Attribute certificate is not valid.", e);
+			}
+		}
+
+		internal static void ProcessAttrCert4(
+			X509Certificate	acIssuerCert,
+			PkixParameters	pkixParams)
+		{
+			ISet set = pkixParams.GetTrustedACIssuers();
+			bool trusted = false;
+			foreach (TrustAnchor anchor in set)
+			{
+                IDictionary symbols = X509Name.RFC2253Symbols;
+                if (acIssuerCert.SubjectDN.ToString(false, symbols).Equals(anchor.CAName)
+					|| acIssuerCert.Equals(anchor.TrustedCert))
+				{
+					trusted = true;
+				}
+			}
+			if (!trusted)
+			{
+				throw new PkixCertPathValidatorException(
+					"Attribute certificate issuer is not directly trusted.");
+			}
+		}
+
+		internal static void ProcessAttrCert3(
+			X509Certificate	acIssuerCert,
+			PkixParameters	pkixParams)
+		{
+			if (acIssuerCert.GetKeyUsage() != null
+				&& (!acIssuerCert.GetKeyUsage()[0] && !acIssuerCert.GetKeyUsage()[1]))
+			{
+				throw new PkixCertPathValidatorException(
+					"Attribute certificate issuer public key cannot be used to validate digital signatures.");
+			}
+			if (acIssuerCert.GetBasicConstraints() != -1)
+			{
+				throw new PkixCertPathValidatorException(
+					"Attribute certificate issuer is also a public key certificate issuer.");
+			}
+		}
+
+		internal static PkixCertPathValidatorResult ProcessAttrCert2(
+			PkixCertPath	certPath,
+			PkixParameters	pkixParams)
+		{
+			PkixCertPathValidator validator = new PkixCertPathValidator();
+
+			try
+			{
+				return validator.Validate(certPath, pkixParams);
+			}
+			catch (PkixCertPathValidatorException e)
+			{
+				throw new PkixCertPathValidatorException(
+					"Certification path for issuer certificate of attribute certificate could not be validated.",
+					e);
+			}
+		}
+
+		/**
+		* Searches for a holder public key certificate and verifies its
+		* certification path.
+		* 
+		* @param attrCert the attribute certificate.
+		* @param pkixParams The PKIX parameters.
+		* @return The certificate path of the holder certificate.
+		* @throws Exception if
+		*             <ul>
+		*             <li>no public key certificate can be found although holder
+		*             information is given by an entity name or a base certificate
+		*             ID</li>
+		*             <li>support classes cannot be created</li>
+		*             <li>no certification path for the public key certificate can
+		*             be built</li>
+		*             </ul>
+		*/
+		internal static PkixCertPath ProcessAttrCert1(
+			IX509AttributeCertificate	attrCert,
+			PkixParameters				pkixParams)
+		{
+			PkixCertPathBuilderResult result = null;
+			// find holder PKCs
+			ISet holderPKCs = new HashSet();
+			if (attrCert.Holder.GetIssuer() != null)
+			{
+				X509CertStoreSelector selector = new X509CertStoreSelector();
+				selector.SerialNumber = attrCert.Holder.SerialNumber;
+				X509Name[] principals = attrCert.Holder.GetIssuer();
+				for (int i = 0; i < principals.Length; i++)
+				{
+					try
+					{
+//						if (principals[i] is X500Principal)
+						{
+							selector.Issuer = principals[i];
+						}
+						holderPKCs.AddAll(PkixCertPathValidatorUtilities
+							.FindCertificates(selector, pkixParams.GetStores()));
+					}
+					catch (Exception e)
+					{
+						throw new PkixCertPathValidatorException(
+							"Public key certificate for attribute certificate cannot be searched.",
+							e);
+					}
+				}
+				if (holderPKCs.IsEmpty)
+				{
+					throw new PkixCertPathValidatorException(
+						"Public key certificate specified in base certificate ID for attribute certificate cannot be found.");
+				}
+			}
+			if (attrCert.Holder.GetEntityNames() != null)
+			{
+				X509CertStoreSelector selector = new X509CertStoreSelector();
+				X509Name[] principals = attrCert.Holder.GetEntityNames();
+				for (int i = 0; i < principals.Length; i++)
+				{
+					try
+					{
+//						if (principals[i] is X500Principal)
+						{
+							selector.Issuer = principals[i];
+						}
+						holderPKCs.AddAll(PkixCertPathValidatorUtilities
+							.FindCertificates(selector, pkixParams.GetStores()));
+					}
+					catch (Exception e)
+					{
+						throw new PkixCertPathValidatorException(
+							"Public key certificate for attribute certificate cannot be searched.",
+							e);
+					}
+				}
+				if (holderPKCs.IsEmpty)
+				{
+					throw new PkixCertPathValidatorException(
+						"Public key certificate specified in entity name for attribute certificate cannot be found.");
+				}
+			}
+
+			// verify cert paths for PKCs
+			PkixBuilderParameters parameters = (PkixBuilderParameters)
+				PkixBuilderParameters.GetInstance(pkixParams);
+
+			PkixCertPathValidatorException lastException = null;
+			foreach (X509Certificate cert in holderPKCs)
+			{
+				X509CertStoreSelector selector = new X509CertStoreSelector();
+				selector.Certificate = cert;
+				parameters.SetTargetConstraints(selector);
+
+				PkixCertPathBuilder builder = new PkixCertPathBuilder();
+
+				try
+				{
+					result = builder.Build(PkixBuilderParameters.GetInstance(parameters));
+				}
+				catch (PkixCertPathBuilderException e)
+				{
+					lastException = new PkixCertPathValidatorException(
+						"Certification path for public key certificate of attribute certificate could not be build.",
+						e);
+				}
+			}
+			if (lastException != null)
+			{
+				throw lastException;
+			}
+			return result.CertPath;
+		}
+
+		/**
+		* 
+		* Checks a distribution point for revocation information for the
+		* certificate <code>attrCert</code>.
+		* 
+		* @param dp The distribution point to consider.
+		* @param attrCert The attribute certificate which should be checked.
+		* @param paramsPKIX PKIX parameters.
+		* @param validDate The date when the certificate revocation status should
+		*            be checked.
+		* @param issuerCert Certificate to check if it is revoked.
+		* @param reasonMask The reasons mask which is already checked.
+		* @param certPathCerts The certificates of the certification path to be
+		*            checked.
+		* @throws Exception if the certificate is revoked or the status
+		*             cannot be checked or some error occurs.
+		*/
+		private static void CheckCrl(
+			DistributionPoint			dp,
+			IX509AttributeCertificate	attrCert,
+			PkixParameters				paramsPKIX,
+			DateTime					validDate,
+			X509Certificate				issuerCert,
+			CertStatus					certStatus,
+			ReasonsMask					reasonMask,
+			IList						certPathCerts)
+		{
+			/*
+			* 4.3.6 No Revocation Available
+			* 
+			* The noRevAvail extension, defined in [X.509-2000], allows an AC
+			* issuer to indicate that no revocation information will be made
+			* available for this AC.
+			*/
+			if (attrCert.GetExtensionValue(X509Extensions.NoRevAvail) != null)
+			{
+				return;
+			}
+
+			DateTime currentDate = DateTime.UtcNow;
+			if (validDate.CompareTo(currentDate) > 0)
+			{
+				throw new Exception("Validation time is in future.");
+			}
+
+			// (a)
+			/*
+			* We always get timely valid CRLs, so there is no step (a) (1).
+			* "locally cached" CRLs are assumed to be in getStore(), additional
+			* CRLs must be enabled in the ExtendedPkixParameters and are in
+			* getAdditionalStore()
+			*/
+			ISet crls = PkixCertPathValidatorUtilities.GetCompleteCrls(dp, attrCert,
+				currentDate, paramsPKIX);
+			bool validCrlFound = false;
+			Exception lastException = null;
+
+			IEnumerator crl_iter = crls.GetEnumerator();
+
+			while (crl_iter.MoveNext()
+				&& certStatus.Status == CertStatus.Unrevoked
+				&& !reasonMask.IsAllReasons)
+			{
+				try
+				{
+					X509Crl crl = (X509Crl) crl_iter.Current;
+
+					// (d)
+					ReasonsMask interimReasonsMask = Rfc3280CertPathUtilities.ProcessCrlD(crl, dp);
+
+					// (e)
+					/*
+					* The reasons mask is updated at the end, so only valid CRLs
+					* can update it. If this CRL does not contain new reasons it
+					* must be ignored.
+					*/
+					if (!interimReasonsMask.HasNewReasons(reasonMask))
+					{
+						continue;
+					}
+
+					// (f)
+					ISet keys = Rfc3280CertPathUtilities.ProcessCrlF(crl, attrCert,
+						null, null, paramsPKIX, certPathCerts);
+					// (g)
+					AsymmetricKeyParameter pubKey = Rfc3280CertPathUtilities.ProcessCrlG(crl, keys);
+
+					X509Crl deltaCRL = null;
+
+					if (paramsPKIX.IsUseDeltasEnabled)
+					{
+						// get delta CRLs
+						ISet deltaCRLs = PkixCertPathValidatorUtilities.GetDeltaCrls(
+							currentDate, paramsPKIX, crl);
+						// we only want one valid delta CRL
+						// (h)
+						deltaCRL = Rfc3280CertPathUtilities.ProcessCrlH(deltaCRLs, pubKey);
+					}
+
+					/*
+					* CRL must be be valid at the current time, not the validation
+					* time. If a certificate is revoked with reason keyCompromise,
+					* cACompromise, it can be used for forgery, also for the past.
+					* This reason may not be contained in older CRLs.
+					*/
+
+					/*
+					* in the chain model signatures stay valid also after the
+					* certificate has been expired, so they do not have to be in
+					* the CRL vality time
+					*/
+					if (paramsPKIX.ValidityModel != PkixParameters.ChainValidityModel)
+					{
+						/*
+						* if a certificate has expired, but was revoked, it is not
+						* more in the CRL, so it would be regarded as valid if the
+						* first check is not done
+						*/
+						if (attrCert.NotAfter.CompareTo(crl.ThisUpdate) < 0)
+						{
+							throw new Exception(
+								"No valid CRL for current time found.");
+						}
+					}
+
+					Rfc3280CertPathUtilities.ProcessCrlB1(dp, attrCert, crl);
+
+					// (b) (2)
+					Rfc3280CertPathUtilities.ProcessCrlB2(dp, attrCert, crl);
+
+					// (c)
+					Rfc3280CertPathUtilities.ProcessCrlC(deltaCRL, crl, paramsPKIX);
+
+					// (i)
+					Rfc3280CertPathUtilities.ProcessCrlI(validDate, deltaCRL,
+						attrCert, certStatus, paramsPKIX);
+
+					// (j)
+					Rfc3280CertPathUtilities.ProcessCrlJ(validDate, crl, attrCert,
+						certStatus);
+
+					// (k)
+					if (certStatus.Status == CrlReason.RemoveFromCrl)
+					{
+						certStatus.Status = CertStatus.Unrevoked;
+					}
+
+					// update reasons mask
+					reasonMask.AddReasons(interimReasonsMask);
+					validCrlFound = true;
+				}
+				catch (Exception e)
+				{
+					lastException = e;
+				}
+			}
+			if (!validCrlFound)
+			{
+				throw lastException;
+			}
+		}
+	}
+}
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
new file mode 100644
index 000000000..d74ec7368
--- /dev/null
+++ b/Crypto/src/security/AgreementUtilities.cs
@@ -0,0 +1,106 @@
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Agreement;
+using Org.BouncyCastle.Crypto.Agreement.Kdf;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+	/// <remarks>
+	///  Utility class for creating IBasicAgreement objects from their names/Oids
+	/// </remarks>
+	public sealed class AgreementUtilities
+	{
+		private AgreementUtilities()
+		{
+		}
+
+		private static readonly IDictionary algorithms = Platform.CreateHashtable();
+        //private static readonly IDictionary oids = Platform.CreateHashtable();
+
+		static AgreementUtilities()
+		{
+			//algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = ?;
+			algorithms[X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id] = "ECDHWITHSHA1KDF";
+			algorithms[X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id] = "ECMQVWITHSHA1KDF";
+		}
+
+		public static IBasicAgreement GetBasicAgreement(
+			DerObjectIdentifier oid)
+		{
+			return GetBasicAgreement(oid.Id);
+		}
+
+		public static IBasicAgreement GetBasicAgreement(
+			string algorithm)
+		{
+			string upper = algorithm.ToUpperInvariant();
+			string mechanism = (string) algorithms[upper];
+
+			if (mechanism == null)
+			{
+				mechanism = upper;
+			}
+
+			if (mechanism == "DH" || mechanism == "DIFFIEHELLMAN")
+				return new DHBasicAgreement();
+
+			if (mechanism == "ECDH")
+				return new ECDHBasicAgreement();
+
+			if (mechanism == "ECDHC")
+				return new ECDHCBasicAgreement();
+
+			if (mechanism == "ECMQV")
+				return new ECMqvBasicAgreement();
+
+			throw new SecurityUtilityException("Basic Agreement " + algorithm + " not recognised.");
+		}
+
+		public static IBasicAgreement GetBasicAgreementWithKdf(
+			DerObjectIdentifier oid,
+			string				wrapAlgorithm)
+		{
+			return GetBasicAgreementWithKdf(oid.Id, wrapAlgorithm);
+		}
+
+		public static IBasicAgreement GetBasicAgreementWithKdf(
+			string agreeAlgorithm,
+			string wrapAlgorithm)
+		{
+			string upper = agreeAlgorithm.ToUpperInvariant();
+			string mechanism = (string) algorithms[upper];
+
+			if (mechanism == null)
+			{
+				mechanism = upper;
+			}
+
+			// 'DHWITHSHA1KDF' retained for backward compatibility
+			if (mechanism == "DHWITHSHA1KDF" || mechanism == "ECDHWITHSHA1KDF")
+				return new ECDHWithKdfBasicAgreement(
+					wrapAlgorithm,
+					new ECDHKekGenerator(
+						new Sha1Digest()));
+
+			if (mechanism == "ECMQVWITHSHA1KDF")
+				return new ECMqvWithKdfBasicAgreement(
+					wrapAlgorithm,
+					new ECDHKekGenerator(
+						new Sha1Digest()));
+
+			throw new SecurityUtilityException("Basic Agreement (with KDF) " + agreeAlgorithm + " not recognised.");
+		}
+
+		public static string GetAlgorithmName(
+			DerObjectIdentifier oid)
+		{
+			return (string) algorithms[oid.Id];
+		}
+	}
+}
diff --git a/Crypto/src/security/CipherUtilities.cs b/Crypto/src/security/CipherUtilities.cs
new file mode 100644
index 000000000..ffd7d1373
--- /dev/null
+++ b/Crypto/src/security/CipherUtilities.cs
@@ -0,0 +1,696 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+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.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.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();
+        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();
+
+			// 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.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.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[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["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;
+		}
+	}
+}
diff --git a/Crypto/src/security/DigestUtilities.cs b/Crypto/src/security/DigestUtilities.cs
new file mode 100644
index 000000000..a507b4e9b
--- /dev/null
+++ b/Crypto/src/security/DigestUtilities.cs
@@ -0,0 +1,189 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+    /// <remarks>
+    ///  Utility class for creating IDigest objects from their names/Oids
+    /// </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 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();
+			
+            algorithms[PkcsObjectIdentifiers.MD2.Id] = "MD2";
+            algorithms[PkcsObjectIdentifiers.MD4.Id] = "MD4";
+            algorithms[PkcsObjectIdentifiers.MD5.Id] = "MD5";
+
+            algorithms["SHA1"] = "SHA-1";
+            algorithms[OiwObjectIdentifiers.IdSha1.Id] = "SHA-1";
+            algorithms["SHA224"] = "SHA-224";
+            algorithms[NistObjectIdentifiers.IdSha224.Id] = "SHA-224";
+            algorithms["SHA256"] = "SHA-256";
+            algorithms[NistObjectIdentifiers.IdSha256.Id] = "SHA-256";
+            algorithms["SHA384"] = "SHA-384";
+            algorithms[NistObjectIdentifiers.IdSha384.Id] = "SHA-384";
+            algorithms["SHA512"] = "SHA-512";
+            algorithms[NistObjectIdentifiers.IdSha512.Id] = "SHA-512";
+
+            algorithms["RIPEMD-128"] = "RIPEMD128";
+            algorithms[TeleTrusTObjectIdentifiers.RipeMD128.Id] = "RIPEMD128";
+            algorithms["RIPEMD-160"] = "RIPEMD160";
+            algorithms[TeleTrusTObjectIdentifiers.RipeMD160.Id] = "RIPEMD160";
+            algorithms["RIPEMD-256"] = "RIPEMD256";
+            algorithms[TeleTrusTObjectIdentifiers.RipeMD256.Id] = "RIPEMD256";
+			algorithms["RIPEMD-320"] = "RIPEMD320";
+//			algorithms[TeleTrusTObjectIdentifiers.RipeMD320.Id] = "RIPEMD320";
+
+			algorithms[CryptoProObjectIdentifiers.GostR3411.Id] = "GOST3411";
+
+
+
+            oids["MD2"] = PkcsObjectIdentifiers.MD2;
+            oids["MD4"] = PkcsObjectIdentifiers.MD4;
+            oids["MD5"] = PkcsObjectIdentifiers.MD5;
+            oids["SHA-1"] = OiwObjectIdentifiers.IdSha1;
+            oids["SHA-224"] = NistObjectIdentifiers.IdSha224;
+            oids["SHA-256"] = NistObjectIdentifiers.IdSha256;
+            oids["SHA-384"] = NistObjectIdentifiers.IdSha384;
+            oids["SHA-512"] = NistObjectIdentifiers.IdSha512;
+            oids["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
+            oids["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
+            oids["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
+			oids["GOST3411"] = CryptoProObjectIdentifiers.GostR3411;
+        }
+
+		/// <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)
+        {
+			if (mechanism == null)
+				throw new System.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 IDigest GetDigest(
+			DerObjectIdentifier id)
+        {
+            return GetDigest(id.Id);
+        }
+
+        public static IDigest GetDigest(
+			string algorithm)
+        {
+			string upper = algorithm.ToUpperInvariant();
+            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.");
+        }
+
+		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);
+		}
+    }
+}
diff --git a/Crypto/src/security/DotNetUtilities.cs b/Crypto/src/security/DotNetUtilities.cs
new file mode 100644
index 000000000..4df1ae739
--- /dev/null
+++ b/Crypto/src/security/DotNetUtilities.cs
@@ -0,0 +1,222 @@
+#if !(NETCF_1_0 || SILVERLIGHT || PORTABLE)
+
+using System;
+using System.Security.Cryptography;
+using SystemX509 = System.Security.Cryptography.X509Certificates;
+
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Security
+{
+	/// <summary>
+	/// A class containing methods to interface the BouncyCastle world to the .NET Crypto world.
+	/// </summary>
+	public sealed class DotNetUtilities
+	{
+		private DotNetUtilities()
+		{
+		}
+
+		/// <summary>
+		/// Create an System.Security.Cryptography.X509Certificate from an X509Certificate Structure.
+		/// </summary>
+		/// <param name="x509Struct"></param>
+		/// <returns>A System.Security.Cryptography.X509Certificate.</returns>
+		public static SystemX509.X509Certificate ToX509Certificate(
+			X509CertificateStructure x509Struct)
+		{
+			return new SystemX509.X509Certificate(x509Struct.GetDerEncoded());
+		}
+
+		public static SystemX509.X509Certificate ToX509Certificate(
+			X509Certificate x509Cert)
+		{
+			return new SystemX509.X509Certificate(x509Cert.GetEncoded());
+		}
+
+		public static X509Certificate FromX509Certificate(
+			SystemX509.X509Certificate x509Cert)
+		{
+			return new X509CertificateParser().ReadCertificate(x509Cert.GetRawCertData());
+		}
+
+		public static AsymmetricCipherKeyPair GetDsaKeyPair(
+			DSA dsa)
+		{
+			return GetDsaKeyPair(dsa.ExportParameters(true));
+		}
+
+		public static AsymmetricCipherKeyPair GetDsaKeyPair(
+			DSAParameters dp)
+		{
+			DsaValidationParameters validationParameters = (dp.Seed != null)
+				?	new DsaValidationParameters(dp.Seed, dp.Counter)
+				:	null;
+
+			DsaParameters parameters = new DsaParameters(
+				new BigInteger(1, dp.P),
+				new BigInteger(1, dp.Q),
+				new BigInteger(1, dp.G),
+				validationParameters);
+
+			DsaPublicKeyParameters pubKey = new DsaPublicKeyParameters(
+				new BigInteger(1, dp.Y),
+				parameters);
+
+			DsaPrivateKeyParameters privKey = new DsaPrivateKeyParameters(
+				new BigInteger(1, dp.X),
+				parameters);
+
+			return new AsymmetricCipherKeyPair(pubKey, privKey);
+		}
+
+		public static DsaPublicKeyParameters GetDsaPublicKey(
+			DSA dsa)
+		{
+			return GetDsaPublicKey(dsa.ExportParameters(false));
+		}
+
+		public static DsaPublicKeyParameters GetDsaPublicKey(
+			DSAParameters dp)
+		{
+			DsaValidationParameters validationParameters = (dp.Seed != null)
+				?	new DsaValidationParameters(dp.Seed, dp.Counter)
+				:	null;
+
+			DsaParameters parameters = new DsaParameters(
+				new BigInteger(1, dp.P),
+				new BigInteger(1, dp.Q),
+				new BigInteger(1, dp.G),
+				validationParameters);
+
+			return new DsaPublicKeyParameters(
+				new BigInteger(1, dp.Y),
+				parameters);
+		}
+
+		public static AsymmetricCipherKeyPair GetRsaKeyPair(
+			RSA rsa)
+		{
+			return GetRsaKeyPair(rsa.ExportParameters(true));
+		}
+
+		public static AsymmetricCipherKeyPair GetRsaKeyPair(
+			RSAParameters rp)
+		{
+			BigInteger modulus = new BigInteger(1, rp.Modulus);
+			BigInteger pubExp = new BigInteger(1, rp.Exponent);
+
+			RsaKeyParameters pubKey = new RsaKeyParameters(
+				false,
+				modulus,
+				pubExp);
+
+			RsaPrivateCrtKeyParameters privKey = new RsaPrivateCrtKeyParameters(
+				modulus,
+				pubExp,
+				new BigInteger(1, rp.D),
+				new BigInteger(1, rp.P),
+				new BigInteger(1, rp.Q),
+				new BigInteger(1, rp.DP),
+				new BigInteger(1, rp.DQ),
+				new BigInteger(1, rp.InverseQ));
+
+			return new AsymmetricCipherKeyPair(pubKey, privKey);
+		}
+
+		public static RsaKeyParameters GetRsaPublicKey(
+			RSA rsa)
+		{
+			return GetRsaPublicKey(rsa.ExportParameters(false));
+		}
+
+		public static RsaKeyParameters GetRsaPublicKey(
+			RSAParameters rp)
+		{
+			return new RsaKeyParameters(
+				false,
+				new BigInteger(1, rp.Modulus),
+				new BigInteger(1, rp.Exponent));
+		}
+
+		public static AsymmetricCipherKeyPair GetKeyPair(AsymmetricAlgorithm privateKey)
+		{
+			if (privateKey is DSA)
+			{
+				return GetDsaKeyPair((DSA)privateKey);
+			}
+
+			if (privateKey is RSA)
+			{
+				return GetRsaKeyPair((RSA)privateKey);
+			}
+
+			throw new ArgumentException("Unsupported algorithm specified", "privateKey");
+		}
+
+		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;
+		}
+
+		public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
+		{
+			RSAParameters rp = ToRSAParameters(privKey);
+			RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider();
+			rsaCsp.ImportParameters(rp);
+			return rsaCsp;
+		}
+
+		public static RSAParameters ToRSAParameters(RsaKeyParameters rsaKey)
+		{
+			RSAParameters rp = new RSAParameters();
+			rp.Modulus = rsaKey.Modulus.ToByteArrayUnsigned();
+			if (rsaKey.IsPrivate)
+				rp.D = ConvertRSAParametersField(rsaKey.Exponent, rp.Modulus.Length);
+			else
+				rp.Exponent = rsaKey.Exponent.ToByteArrayUnsigned();
+			return rp;
+		}
+
+		public static RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey)
+		{
+			RSAParameters rp = new RSAParameters();
+			rp.Modulus = privKey.Modulus.ToByteArrayUnsigned();
+			rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned();
+			rp.P = privKey.P.ToByteArrayUnsigned();
+			rp.Q = privKey.Q.ToByteArrayUnsigned();
+			rp.D = ConvertRSAParametersField(privKey.Exponent, rp.Modulus.Length);
+			rp.DP = ConvertRSAParametersField(privKey.DP, rp.P.Length);
+			rp.DQ = ConvertRSAParametersField(privKey.DQ, rp.Q.Length);
+			rp.InverseQ = ConvertRSAParametersField(privKey.QInv, rp.Q.Length);
+			return rp;
+		}
+
+		// TODO Move functionality to more general class
+		private static byte[] ConvertRSAParametersField(BigInteger n, int size)
+		{
+			byte[] bs = n.ToByteArrayUnsigned();
+
+			if (bs.Length == size)
+				return bs;
+
+			if (bs.Length > size)
+				throw new ArgumentException("Specified size too small", "size");
+
+			byte[] padded = new byte[size];
+			Array.Copy(bs, 0, padded, size - bs.Length, bs.Length);
+			return padded;
+		}
+	}
+}
+
+#endif
diff --git a/Crypto/src/security/GeneralSecurityException.cs b/Crypto/src/security/GeneralSecurityException.cs
new file mode 100644
index 000000000..c0e412f98
--- /dev/null
+++ b/Crypto/src/security/GeneralSecurityException.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+	public class GeneralSecurityException
+		: Exception
+	{
+		public GeneralSecurityException()
+			: base()
+		{
+		}
+
+		public GeneralSecurityException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public GeneralSecurityException(
+			string		message,
+			Exception	exception)
+			: base(message, exception)
+		{
+		}
+	}
+}
diff --git a/Crypto/src/security/GeneratorUtilities.cs b/Crypto/src/security/GeneratorUtilities.cs
new file mode 100644
index 000000000..8e9290222
--- /dev/null
+++ b/Crypto/src/security/GeneratorUtilities.cs
@@ -0,0 +1,341 @@
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Iana;
+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.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Security
+{
+	public sealed class GeneratorUtilities
+	{
+		private GeneratorUtilities()
+		{
+		}
+
+		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",
+                "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];
+		}
+	}
+}
diff --git a/Crypto/src/security/InvalidKeyException.cs b/Crypto/src/security/InvalidKeyException.cs
new file mode 100644
index 000000000..97d48e091
--- /dev/null
+++ b/Crypto/src/security/InvalidKeyException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+	public class InvalidKeyException : KeyException
+	{
+		public InvalidKeyException() : base() { }
+		public InvalidKeyException(string message) : base(message) { }
+		public InvalidKeyException(string message, Exception exception) : base(message, exception) { }
+	}
+}
diff --git a/Crypto/src/security/InvalidParameterException.cs b/Crypto/src/security/InvalidParameterException.cs
new file mode 100644
index 000000000..08ca4a076
--- /dev/null
+++ b/Crypto/src/security/InvalidParameterException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+	public class InvalidParameterException : KeyException
+	{
+		public InvalidParameterException() : base() { }
+		public InvalidParameterException(string message) : base(message) { }
+		public InvalidParameterException(string message, Exception exception) : base(message, exception) { }
+	}
+}
diff --git a/Crypto/src/security/KeyException.cs b/Crypto/src/security/KeyException.cs
new file mode 100644
index 000000000..f19264e5f
--- /dev/null
+++ b/Crypto/src/security/KeyException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+	public class KeyException : GeneralSecurityException
+	{
+		public KeyException() : base() { }
+		public KeyException(string message) : base(message) { }
+		public KeyException(string message, Exception exception) : base(message, exception) { }
+	}
+}
diff --git a/Crypto/src/security/MacUtilities.cs b/Crypto/src/security/MacUtilities.cs
new file mode 100644
index 000000000..8550d7550
--- /dev/null
+++ b/Crypto/src/security/MacUtilities.cs
@@ -0,0 +1,239 @@
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Iana;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Macs;
+using Org.BouncyCastle.Crypto.Paddings;
+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();
+        //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";
+		}
+
+//		/// <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)
+//		{
+//			mechanism = (string) algorithms[mechanism.ToUpperInvariant()];
+//
+//			if (mechanism != null)
+//			{
+//				return (DerObjectIdentifier)oids[mechanism];
+//			}
+//
+//			return null;
+//		}
+
+//		public static ICollection Algorithms
+//		{
+//			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;
+		}
+	}
+}
diff --git a/Crypto/src/security/NoSuchAlgorithmException.cs b/Crypto/src/security/NoSuchAlgorithmException.cs
new file mode 100644
index 000000000..25c0ab04f
--- /dev/null
+++ b/Crypto/src/security/NoSuchAlgorithmException.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+	[Obsolete("Never thrown")]
+	public class NoSuchAlgorithmException : GeneralSecurityException
+	{
+		public NoSuchAlgorithmException() : base() {}
+		public NoSuchAlgorithmException(string message) : base(message) {}
+		public NoSuchAlgorithmException(string message, Exception exception) : base(message, exception) {}
+	}
+}
diff --git a/Crypto/src/security/ParameterUtilities.cs b/Crypto/src/security/ParameterUtilities.cs
new file mode 100644
index 000000000..b44fbda73
--- /dev/null
+++ b/Crypto/src/security/ParameterUtilities.cs
@@ -0,0 +1,327 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Misc;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+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];
+		}
+	}
+}
diff --git a/Crypto/src/security/PbeUtilities.cs b/Crypto/src/security/PbeUtilities.cs
new file mode 100644
index 000000000..f59ab104b
--- /dev/null
+++ b/Crypto/src/security/PbeUtilities.cs
@@ -0,0 +1,658 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.BC;
+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.Digests;
+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.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();
+        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";
+//			algorithms[PkcsObjectIdentifiers.IdPbkdf2.Id] = "Pkcs5scheme2";
+
+			// 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);
+		}
+	}
+}
diff --git a/Crypto/src/security/PrivateKeyFactory.cs b/Crypto/src/security/PrivateKeyFactory.cs
new file mode 100644
index 000000000..5ebebd55a
--- /dev/null
+++ b/Crypto/src/security/PrivateKeyFactory.cs
@@ -0,0 +1,221 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+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;
+
+namespace Org.BouncyCastle.Security
+{
+    public sealed class PrivateKeyFactory
+    {
+        private PrivateKeyFactory()
+        {
+        }
+
+		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)
+        {
+            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?
+//			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)
+				{
+                    x9 = ECKeyPairGenerator.FindECCurveByOid((DerObjectIdentifier)para.Parameters);
+				}
+				else
+				{
+                    x9 = new X9ECParameters((Asn1Sequence)para.Parameters);
+				}
+
+                ECPrivateKeyStructure ec = new ECPrivateKeyStructure(
+                    Asn1Sequence.GetInstance(keyInfo.PrivateKey));
+                BigInteger d = ec.GetKey();
+
+                if (para.IsNamedCurve)
+                {
+                    return new ECPrivateKeyParameters("EC", d, (DerObjectIdentifier)para.Parameters);
+                }
+
+                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");
+			}
+        }
+
+		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,
+            char[]					passPhrase,
+            byte[]					salt,
+            int						iterationCount,
+            AsymmetricKeyParameter	key)
+        {
+			return EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+				algorithm, passPhrase, salt, iterationCount, key).GetEncoded();
+        }
+
+		public static byte[] EncryptKey(
+			string					algorithm,
+            char[]					passPhrase,
+            byte[]					salt,
+            int						iterationCount,
+            AsymmetricKeyParameter	key)
+        {
+			return EncryptedPrivateKeyInfoFactory.CreateEncryptedPrivateKeyInfo(
+				algorithm, passPhrase, salt, iterationCount, key).GetEncoded();
+        }
+	}
+}
diff --git a/Crypto/src/security/PublicKeyFactory.cs b/Crypto/src/security/PublicKeyFactory.cs
new file mode 100644
index 000000000..c15e24a41
--- /dev/null
+++ b/Crypto/src/security/PublicKeyFactory.cs
@@ -0,0 +1,253 @@
+using System;
+using System.Collections;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Sec;
+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;
+
+namespace Org.BouncyCastle.Security
+{
+    public sealed class PublicKeyFactory
+    {
+        private PublicKeyFactory()
+        {
+        }
+
+		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());
+
+                X9ECParameters x9;
+				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);
+                ECPoint q = derQ.Point;
+
+                if (para.IsNamedCurve)
+                {
+                    return new ECPublicKeyParameters("EC", q, (DerObjectIdentifier)para.Parameters);
+                }
+
+                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);
+			}
+            else
+            {
+                throw new SecurityUtilityException("algorithm identifier in key not recognised: " + algOid);
+            }
+        }
+
+		private static bool IsPkcsDHParam(Asn1Sequence seq)
+		{
+			if (seq.Count == 2)
+				return true;
+
+			if (seq.Count > 3)
+				return false;
+
+			DerInteger l = DerInteger.GetInstance(seq[2]);
+			DerInteger p = DerInteger.GetInstance(seq[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);
+
+			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);
+		}
+	}
+}
diff --git a/Crypto/src/security/SecureRandom.cs b/Crypto/src/security/SecureRandom.cs
new file mode 100644
index 000000000..866a2cf0d
--- /dev/null
+++ b/Crypto/src/security/SecureRandom.cs
@@ -0,0 +1,228 @@
+using System;
+using System.Globalization;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Prng;
+
+namespace Org.BouncyCastle.Security
+{
+    public class SecureRandom
+		: Random
+    {
+		// Note: all objects of this class should be deriving their random data from
+		// a single generator appropriate to the digest being used.
+		private static readonly IRandomGenerator sha1Generator = new DigestRandomGenerator(new Sha1Digest());
+		private static readonly IRandomGenerator sha256Generator = new DigestRandomGenerator(new Sha256Digest());
+
+		private static readonly SecureRandom[] master = { null };
+		private static SecureRandom Master
+		{
+			get
+			{
+				if (master[0] == null)
+				{
+					IRandomGenerator gen = sha256Generator;
+					gen = new ReversedWindowGenerator(gen, 32);
+					SecureRandom sr = master[0] = new SecureRandom(gen);
+
+					sr.SetSeed(DateTime.Now.Ticks);
+					sr.SetSeed(new ThreadedSeedGenerator().GenerateSeed(24, true));
+					sr.GenerateSeed(1 + sr.Next(32));
+				}
+
+				return master[0];
+			}
+		}
+
+		public static SecureRandom GetInstance(
+			string algorithm)
+		{
+			// 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();
+
+			IRandomGenerator drg = null;
+			if (drgName == "SHA1PRNG")
+			{
+				drg = sha1Generator;
+			}
+			else if (drgName == "SHA256PRNG")
+			{
+				drg = sha256Generator;
+			}
+
+			if (drg != null)
+			{
+				return new SecureRandom(drg);
+			}
+
+			throw new ArgumentException("Unrecognised PRNG algorithm: " + algorithm, "algorithm");
+		}
+
+		public static byte[] GetSeed(
+			int length)
+		{
+			return Master.GenerateSeed(length);
+		}
+
+		protected IRandomGenerator generator;
+
+		public SecureRandom()
+			: this(sha1Generator)
+        {
+			SetSeed(GetSeed(8));
+		}
+
+		public SecureRandom(
+			byte[] inSeed)
+			: this(sha1Generator)
+        {
+			SetSeed(inSeed);
+        }
+
+		/// <summary>Use the specified instance of IRandomGenerator as random source.</summary>
+		/// <remarks>
+		/// This constructor performs no seeding of either the <c>IRandomGenerator</c> or the
+		/// constructed <c>SecureRandom</c>. It is the responsibility of the client to provide
+		/// proper seed material as necessary/appropriate for the given <c>IRandomGenerator</c>
+		/// implementation.
+		/// </remarks>
+		/// <param name="generator">The source to generate all random bytes from.</param>
+		public SecureRandom(
+			IRandomGenerator generator)
+			: base(0)
+		{
+			this.generator = generator;
+		}
+
+		public virtual byte[] GenerateSeed(
+			int length)
+		{
+			SetSeed(DateTime.Now.Ticks);
+
+			byte[] rv = new byte[length];
+			NextBytes(rv);
+			return rv;
+		}
+
+		public virtual void SetSeed(
+			byte[] inSeed)
+        {
+			generator.AddSeedMaterial(inSeed);
+        }
+
+        public virtual void SetSeed(
+			long seed)
+        {
+			generator.AddSeedMaterial(seed);
+		}
+
+		public override int Next()
+		{
+			for (;;)
+			{
+				int i = NextInt() & int.MaxValue;
+
+				if (i != int.MaxValue)
+					return i;
+			}
+		}
+
+		public override int Next(
+			int maxValue)
+		{
+			if (maxValue < 2)
+			{
+				if (maxValue < 0)
+					throw new ArgumentOutOfRangeException("maxValue < 0");
+
+				return 0;
+			}
+
+			// Test whether maxValue is a power of 2
+			if ((maxValue & -maxValue) == maxValue)
+			{
+				int val = NextInt() & int.MaxValue;
+				long lr = ((long) maxValue * (long) val) >> 31;
+				return (int) lr;
+			}
+
+			int bits, result;
+			do
+			{
+				bits = NextInt() & int.MaxValue;
+				result = bits % maxValue;
+			}
+			while (bits - result + (maxValue - 1) < 0); // Ignore results near overflow
+
+			return result;
+		}
+
+		public override int Next(
+			int	minValue,
+			int	maxValue)
+		{
+			if (maxValue <= minValue)
+			{
+				if (maxValue == minValue)
+					return minValue;
+
+				throw new ArgumentException("maxValue cannot be less than minValue");
+			}
+
+			int diff = maxValue - minValue;
+			if (diff > 0)
+				return minValue + Next(diff);
+
+			for (;;)
+			{
+				int i = NextInt();
+
+				if (i >= minValue && i < maxValue)
+					return i;
+			}
+		}
+
+		public override void NextBytes(
+			byte[] buffer)
+        {
+			generator.NextBytes(buffer);
+        }
+
+		public virtual void NextBytes(
+			byte[]	buffer,
+			int		start,
+			int		length)
+		{
+			generator.NextBytes(buffer, start, length);
+		}
+
+		private static readonly double DoubleScale = System.Math.Pow(2.0, 64.0);
+
+		public override double NextDouble()
+		{
+			return Convert.ToDouble((ulong) NextLong()) / DoubleScale;
+		}
+
+		public virtual int NextInt()
+        {
+			byte[] intBytes = new byte[4];
+            NextBytes(intBytes);
+
+			int result = 0;
+            for (int i = 0; i < 4; i++)
+            {
+                result = (result << 8) + (intBytes[i] & 0xff);
+            }
+
+			return result;
+        }
+
+		public virtual long NextLong()
+		{
+			return ((long)(uint) NextInt() << 32) | (long)(uint) NextInt();
+		}
+    }
+}
diff --git a/Crypto/src/security/SecurityUtilityException.cs b/Crypto/src/security/SecurityUtilityException.cs
new file mode 100644
index 000000000..8a5ea68d0
--- /dev/null
+++ b/Crypto/src/security/SecurityUtilityException.cs
@@ -0,0 +1,33 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+    public class SecurityUtilityException
+		: Exception
+    {
+        /**
+        * base constructor.
+        */
+        public SecurityUtilityException()
+        {
+        }
+
+		/**
+         * create a SecurityUtilityException with the given message.
+         *
+         * @param message the message to be carried with the exception.
+         */
+        public SecurityUtilityException(
+            string message)
+			: base(message)
+        {
+        }
+
+		public SecurityUtilityException(
+            string		message,
+            Exception	exception)
+			: base(message, exception)
+        {
+        }
+    }
+}
diff --git a/Crypto/src/security/SignatureException.cs b/Crypto/src/security/SignatureException.cs
new file mode 100644
index 000000000..5ae4cbcf4
--- /dev/null
+++ b/Crypto/src/security/SignatureException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security
+{
+	public class SignatureException : GeneralSecurityException
+	{
+		public SignatureException() : base() { }
+		public SignatureException(string message) : base(message) { }
+		public SignatureException(string message, Exception exception) : base(message, exception) { }
+	}
+}
diff --git a/Crypto/src/security/SignerUtilities.cs b/Crypto/src/security/SignerUtilities.cs
new file mode 100644
index 000000000..ab23ee5d5
--- /dev/null
+++ b/Crypto/src/security/SignerUtilities.cs
@@ -0,0 +1,550 @@
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Signers;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Security
+{
+    /// <summary>
+    ///  Signer Utility class contains methods that can not be specifically grouped into other classes.
+    /// </summary>
+    public sealed class SignerUtilities
+    {
+		private SignerUtilities()
+		{
+		}
+
+		internal static readonly IDictionary algorithms = Platform.CreateHashtable();
+        internal static readonly IDictionary oids = Platform.CreateHashtable();
+
+		static SignerUtilities()
+        {
+			algorithms["MD2WITHRSA"] = "MD2withRSA";
+            algorithms["MD2WITHRSAENCRYPTION"] = "MD2withRSA";
+            algorithms[PkcsObjectIdentifiers.MD2WithRsaEncryption.Id] = "MD2withRSA";
+
+            algorithms["MD4WITHRSA"] = "MD4withRSA";
+            algorithms["MD4WITHRSAENCRYPTION"] = "MD4withRSA";
+            algorithms[PkcsObjectIdentifiers.MD4WithRsaEncryption.Id] = "MD4withRSA";
+
+            algorithms["MD5WITHRSA"] = "MD5withRSA";
+            algorithms["MD5WITHRSAENCRYPTION"] = "MD5withRSA";
+            algorithms[PkcsObjectIdentifiers.MD5WithRsaEncryption.Id] = "MD5withRSA";
+
+            algorithms["SHA1WITHRSA"] = "SHA-1withRSA";
+            algorithms["SHA1WITHRSAENCRYPTION"] = "SHA-1withRSA";
+            algorithms[PkcsObjectIdentifiers.Sha1WithRsaEncryption.Id] = "SHA-1withRSA";
+            algorithms["SHA-1WITHRSA"] = "SHA-1withRSA";
+
+            algorithms["SHA224WITHRSA"] = "SHA-224withRSA";
+            algorithms["SHA224WITHRSAENCRYPTION"] = "SHA-224withRSA";
+            algorithms[PkcsObjectIdentifiers.Sha224WithRsaEncryption.Id] = "SHA-224withRSA";
+            algorithms["SHA-224WITHRSA"] = "SHA-224withRSA";
+
+            algorithms["SHA256WITHRSA"] = "SHA-256withRSA";
+            algorithms["SHA256WITHRSAENCRYPTION"] = "SHA-256withRSA";
+            algorithms[PkcsObjectIdentifiers.Sha256WithRsaEncryption.Id] = "SHA-256withRSA";
+            algorithms["SHA-256WITHRSA"] = "SHA-256withRSA";
+
+            algorithms["SHA384WITHRSA"] = "SHA-384withRSA";
+            algorithms["SHA384WITHRSAENCRYPTION"] = "SHA-384withRSA";
+            algorithms[PkcsObjectIdentifiers.Sha384WithRsaEncryption.Id] = "SHA-384withRSA";
+            algorithms["SHA-384WITHRSA"] = "SHA-384withRSA";
+
+            algorithms["SHA512WITHRSA"] = "SHA-512withRSA";
+            algorithms["SHA512WITHRSAENCRYPTION"] = "SHA-512withRSA";
+            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["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["SHA256WITHRSAANDMGF1"] = "SHA-256withRSAandMGF1";
+            algorithms["SHA-256WITHRSAANDMGF1"] = "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["SHA512WITHRSAANDMGF1"] = "SHA-512withRSAandMGF1";
+            algorithms["SHA-512WITHRSAANDMGF1"] = "SHA-512withRSAandMGF1";
+			algorithms["SHA512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
+			algorithms["SHA-512WITHRSA/PSS"] = "SHA-512withRSAandMGF1";
+
+			algorithms["RIPEMD128WITHRSA"] = "RIPEMD128withRSA";
+            algorithms["RIPEMD128WITHRSAENCRYPTION"] = "RIPEMD128withRSA";
+            algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128.Id] = "RIPEMD128withRSA";
+
+			algorithms["RIPEMD160WITHRSA"] = "RIPEMD160withRSA";
+            algorithms["RIPEMD160WITHRSAENCRYPTION"] = "RIPEMD160withRSA";
+            algorithms[TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160.Id] = "RIPEMD160withRSA";
+
+            algorithms["RIPEMD256WITHRSA"] = "RIPEMD256withRSA";
+            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["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["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;
+            oids["MD4withRSA"] = PkcsObjectIdentifiers.MD4WithRsaEncryption;
+            oids["MD5withRSA"] = PkcsObjectIdentifiers.MD5WithRsaEncryption;
+
+            oids["SHA-1withRSA"] = PkcsObjectIdentifiers.Sha1WithRsaEncryption;
+            oids["SHA-224withRSA"] = PkcsObjectIdentifiers.Sha224WithRsaEncryption;
+            oids["SHA-256withRSA"] = PkcsObjectIdentifiers.Sha256WithRsaEncryption;
+            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["RIPEMD128withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128;
+			oids["RIPEMD160withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160;
+			oids["RIPEMD256withRSA"] = TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256;
+
+			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["GOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94;
+			oids["ECGOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001;
+		}
+
+		/// <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 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)
+        {
+            return GetSigner(id.Id);
+        }
+
+		public static ISigner GetSigner(
+			string algorithm)
+        {
+			if (algorithm == null)
+				throw new ArgumentNullException("algorithm");
+
+			algorithm = algorithm.ToUpperInvariant();
+
+			string mechanism = (string) algorithms[algorithm];
+
+			if (mechanism == null)
+				mechanism = algorithm;
+
+			if (mechanism.Equals("RSA"))
+			{
+				return (new RsaDigestSigner(new NullDigest()));
+			}
+			if (mechanism.Equals("MD2withRSA"))
+            {
+                return (new RsaDigestSigner(new MD2Digest()));
+            }
+            if (mechanism.Equals("MD4withRSA"))
+            {
+                return (new RsaDigestSigner(new MD4Digest()));
+            }
+            if (mechanism.Equals("MD5withRSA"))
+            {
+                return (new RsaDigestSigner(new MD5Digest()));
+            }
+            if (mechanism.Equals("SHA-1withRSA"))
+            {
+                return (new RsaDigestSigner(new Sha1Digest()));
+            }
+            if (mechanism.Equals("SHA-224withRSA"))
+            {
+                return (new RsaDigestSigner(new Sha224Digest()));
+            }
+            if (mechanism.Equals("SHA-256withRSA"))
+            {
+                return (new RsaDigestSigner(new Sha256Digest()));
+            }
+            if (mechanism.Equals("SHA-384withRSA"))
+            {
+                return (new RsaDigestSigner(new Sha384Digest()));
+            }
+            if (mechanism.Equals("SHA-512withRSA"))
+            {
+                return (new RsaDigestSigner(new Sha512Digest()));
+            }
+			if (mechanism.Equals("RIPEMD128withRSA"))
+            {
+                return (new RsaDigestSigner(new RipeMD128Digest()));
+            }
+            if (mechanism.Equals("RIPEMD160withRSA"))
+            {
+                return (new RsaDigestSigner(new RipeMD160Digest()));
+            }
+            if (mechanism.Equals("RIPEMD256withRSA"))
+            {
+                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"))
+            {
+                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"))
+            {
+                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.");
+        }
+
+        public static string GetEncodingName(
+			DerObjectIdentifier oid)
+        {
+            return (string) algorithms[oid.Id];
+        }
+    }
+}
diff --git a/Crypto/src/security/WrapperUtilities.cs b/Crypto/src/security/WrapperUtilities.cs
new file mode 100644
index 000000000..33567c51b
--- /dev/null
+++ b/Crypto/src/security/WrapperUtilities.cs
@@ -0,0 +1,153 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+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();
+        //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);
+			}
+		}
+	}
+}
diff --git a/Crypto/src/security/cert/CertificateEncodingException.cs b/Crypto/src/security/cert/CertificateEncodingException.cs
new file mode 100644
index 000000000..ae6a56653
--- /dev/null
+++ b/Crypto/src/security/cert/CertificateEncodingException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+	public class CertificateEncodingException : CertificateException
+	{
+		public CertificateEncodingException() : base() { }
+		public CertificateEncodingException(string msg) : base(msg) { }
+		public CertificateEncodingException(string msg, Exception e) : base(msg, e) { }
+	}
+}
diff --git a/Crypto/src/security/cert/CertificateException.cs b/Crypto/src/security/cert/CertificateException.cs
new file mode 100644
index 000000000..fa403c7f5
--- /dev/null
+++ b/Crypto/src/security/cert/CertificateException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+	public class CertificateException : GeneralSecurityException
+	{
+		public CertificateException() : base() { }
+		public CertificateException(string message) : base(message) { }
+		public CertificateException(string message, Exception exception) : base(message, exception) { }
+	}
+}
diff --git a/Crypto/src/security/cert/CertificateExpiredException.cs b/Crypto/src/security/cert/CertificateExpiredException.cs
new file mode 100644
index 000000000..33a54806f
--- /dev/null
+++ b/Crypto/src/security/cert/CertificateExpiredException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+	public class CertificateExpiredException : CertificateException
+	{
+		public CertificateExpiredException() : base() { }
+		public CertificateExpiredException(string message) : base(message) { }
+		public CertificateExpiredException(string message, Exception exception) : base(message, exception) { }
+	}
+}
diff --git a/Crypto/src/security/cert/CertificateNotYetValidException.cs b/Crypto/src/security/cert/CertificateNotYetValidException.cs
new file mode 100644
index 000000000..b9210e57c
--- /dev/null
+++ b/Crypto/src/security/cert/CertificateNotYetValidException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+	public class CertificateNotYetValidException : CertificateException
+	{
+		public CertificateNotYetValidException() : base() { }
+		public CertificateNotYetValidException(string message) : base(message) { }
+		public CertificateNotYetValidException(string message, Exception exception) : base(message, exception) { }
+	}
+}
diff --git a/Crypto/src/security/cert/CertificateParsingException.cs b/Crypto/src/security/cert/CertificateParsingException.cs
new file mode 100644
index 000000000..9a1d0111b
--- /dev/null
+++ b/Crypto/src/security/cert/CertificateParsingException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+	public class CertificateParsingException : CertificateException
+	{
+		public CertificateParsingException() : base() { }
+		public CertificateParsingException(string message) : base(message) { }
+		public CertificateParsingException(string message, Exception exception) : base(message, exception) { }
+	}
+}
diff --git a/Crypto/src/security/cert/CrlException.cs b/Crypto/src/security/cert/CrlException.cs
new file mode 100644
index 000000000..59e4f20ea
--- /dev/null
+++ b/Crypto/src/security/cert/CrlException.cs
@@ -0,0 +1,11 @@
+using System;
+
+namespace Org.BouncyCastle.Security.Certificates
+{
+	public class CrlException : GeneralSecurityException
+	{
+		public CrlException() : base() { }
+		public CrlException(string msg) : base(msg) {}
+		public CrlException(string msg, Exception e) : base(msg, e) {}
+	}
+}
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
new file mode 100644
index 000000000..a5e24163d
--- /dev/null
+++ b/Crypto/src/tsp/TSPException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.Tsp
+{
+	public class TspException
+		: Exception
+	{
+		public TspException()
+		{
+		}
+
+		public TspException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public TspException(
+			string		message,
+			Exception	e)
+			: base(message, e)
+		{
+		}
+	}
+}
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
new file mode 100644
index 000000000..d8243e65f
--- /dev/null
+++ b/Crypto/src/tsp/TSPValidationException.cs
@@ -0,0 +1,39 @@
+namespace Org.BouncyCastle.Tsp
+{
+	/**
+	 * Exception thrown if a TSP request or response fails to validate.
+	 * <p>
+	 * If a failure code is associated with the exception it can be retrieved using
+	 * the getFailureCode() method.</p>
+	 */
+	public class TspValidationException
+		: TspException
+	{
+		private int failureCode;
+
+		public TspValidationException(
+			string message)
+			: base(message)
+		{
+			this.failureCode = -1;
+		}
+
+		public TspValidationException(
+			string	message,
+			int		failureCode)
+			: base(message)
+		{
+			this.failureCode = failureCode;
+		}
+
+		/**
+		 * Return the failure code associated with this exception - if one is set.
+		 *
+		 * @return the failure code if set, -1 otherwise.
+		 */
+		public int FailureCode
+		{
+			get { return 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
new file mode 100644
index 000000000..7fa05ebee
--- /dev/null
+++ b/Crypto/src/util/Arrays.cs
@@ -0,0 +1,226 @@
+using System;
+using System.Text;
+
+namespace Org.BouncyCastle.Utilities
+{
+
+    /// <summary> General array utilities.</summary>
+    public sealed class Arrays
+    {
+        private Arrays()
+        {
+        }
+
+		public static bool AreEqual(
+			bool[]  a,
+			bool[]  b)
+		{
+			if (a == b)
+				return true;
+
+			if (a == null || b == null)
+				return false;
+
+            return HaveSameContents(a, b);
+		}
+
+        public static bool AreEqual(
+            char[] a,
+            char[] b)
+        {
+            if (a == b)
+                return true;
+
+            if (a == null || b == null)
+                return false;
+
+            return HaveSameContents(a, b);
+        }
+
+        /// <summary>
+        /// Are two arrays equal.
+        /// </summary>
+        /// <param name="a">Left side.</param>
+        /// <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);
+		}
+
+        private static bool HaveSameContents(
+            bool[] a,
+            bool[] 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(
+            char[] a,
+            char[] 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(
+			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;
+		}
+
+        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;
+			}
+		}
+	}
+}
diff --git a/Crypto/src/util/BigIntegers.cs b/Crypto/src/util/BigIntegers.cs
new file mode 100644
index 000000000..df82e1f22
--- /dev/null
+++ b/Crypto/src/util/BigIntegers.cs
@@ -0,0 +1,72 @@
+using System;
+
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Utilities
+{
+	/**
+	 * BigInteger utilities.
+	 */
+	public sealed 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 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'");
+
+				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
new file mode 100644
index 000000000..abab5266b
--- /dev/null
+++ b/Crypto/src/util/Enums.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Text;
+
+#if NETCF_1_0 || NETCF_2_0 || SILVERLIGHT || PORTABLE
+using System.Collections;
+using System.Reflection;
+#endif
+
+using Org.BouncyCastle.Utilities.Date;
+
+namespace Org.BouncyCastle.Utilities
+{
+    internal sealed class Enums
+    {
+        private Enums()
+        {
+        }
+
+		internal static Enum GetEnumValue(System.Type enumType, string s)
+		{
+			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('-', '_');
+
+#if NETCF_1_0
+				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);
+#endif		
+			}
+
+			throw new ArgumentException();
+		}
+
+		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
+            IList result = Platform.CreateArrayList();
+			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));
+			}
+            object[] arr = new object[result.Count];
+            result.CopyTo(arr, 0);
+            return arr;
+#else
+			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);
+		}
+	}
+}
diff --git a/Crypto/src/util/Platform.cs b/Crypto/src/util/Platform.cs
new file mode 100644
index 000000000..52ace89e5
--- /dev/null
+++ b/Crypto/src/util/Platform.cs
@@ -0,0 +1,171 @@
+using System;
+using System.IO;
+using System.Text;
+
+#if SILVERLIGHT || PORTABLE
+using System.Collections.Generic;
+#else
+using System.Collections;
+#endif
+
+namespace Org.BouncyCastle.Utilities
+{
+	internal sealed class Platform
+	{
+		private 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();
+            return Encoding.UTF8.GetString(bs, 0, bs.Length);
+		}
+#else
+        private static string GetNewLine()
+        {
+            return Environment.NewLine;
+        }
+#endif
+
+        internal static int CompareIgnoreCase(string a, string b)
+        {
+#if (SILVERLIGHT || PORTABLE)
+            return String.Compare(a, b, StringComparison.OrdinalIgnoreCase);
+#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;
+		}
+#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;
+			}
+		}
+#endif
+
+#if NETCF_1_0
+		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));
+		}
+#else
+		internal static Exception CreateNotImplementedException(
+			string message)
+		{
+			return new NotImplementedException(message);
+		}
+#endif
+
+#if SILVERLIGHT || PORTABLE
+        internal static System.Collections.IList CreateArrayList()
+        {
+            return new List<object>();
+        }
+        internal static System.Collections.IList CreateArrayList(int capacity)
+        {
+            return new List<object>(capacity);
+        }
+        internal static System.Collections.IList CreateArrayList(System.Collections.ICollection collection)
+        {
+            System.Collections.IList result = new List<object>(collection.Count);
+            foreach (object o in collection)
+            {
+                result.Add(o);
+            }
+            return result;
+        }
+        internal static System.Collections.IList CreateArrayList(System.Collections.IEnumerable collection)
+        {
+            System.Collections.IList result = new List<object>();
+            foreach (object o in collection)
+            {
+                result.Add(o);
+            }
+            return result;
+        }
+        internal static System.Collections.IDictionary CreateHashtable()
+        {
+            return new Dictionary<object, object>();
+        }
+        internal static System.Collections.IDictionary CreateHashtable(int capacity)
+        {
+            return new Dictionary<object, object>(capacity);
+        }
+        internal static System.Collections.IDictionary CreateHashtable(System.Collections.IDictionary dictionary)
+        {
+            System.Collections.IDictionary result = new Dictionary<object, object>(dictionary.Count);
+            foreach (System.Collections.DictionaryEntry entry in dictionary)
+            {
+                result.Add(entry.Key, entry.Value);
+            }
+            return result;
+        }
+#else
+        internal static System.Collections.IList CreateArrayList()
+        {
+            return new ArrayList();
+        }
+        internal static System.Collections.IList CreateArrayList(int capacity)
+        {
+            return new ArrayList(capacity);
+        }
+        internal static System.Collections.IList CreateArrayList(System.Collections.ICollection collection)
+        {
+            return new ArrayList(collection);
+        }
+        internal static System.Collections.IList CreateArrayList(System.Collections.IEnumerable collection)
+        {
+            ArrayList result = new ArrayList();
+            foreach (object o in collection)
+            {
+                result.Add(o);
+            }
+            return result;
+        }
+        internal static System.Collections.IDictionary CreateHashtable()
+        {
+            return new Hashtable();
+        }
+        internal static System.Collections.IDictionary CreateHashtable(int capacity)
+        {
+            return new Hashtable(capacity);
+        }
+        internal static System.Collections.IDictionary CreateHashtable(System.Collections.IDictionary dictionary)
+        {
+            return new Hashtable(dictionary);
+        }
+#endif
+
+        internal static readonly string NewLine = GetNewLine();
+	}
+}
diff --git a/Crypto/src/util/Strings.cs b/Crypto/src/util/Strings.cs
new file mode 100644
index 000000000..1d35920c9
--- /dev/null
+++ b/Crypto/src/util/Strings.cs
@@ -0,0 +1,107 @@
+using System;
+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;
+		}
+
+		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)
+        {
+            byte[] bs = new byte[cs.Length];
+            for (int i = 0; i < bs.Length; ++i)
+            {
+                bs[i] = Convert.ToByte(cs[i]);
+            }
+            return bs;
+        }
+
+        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;
+		}
+
+        public static string FromAsciiByteArray(
+            byte[] bytes)
+        {
+#if (SILVERLIGHT || PORTABLE)
+            // TODO Check for non-ASCII bytes in input?
+            return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
+#else
+            return Encoding.ASCII.GetString(bytes, 0, bytes.Length);
+#endif
+        }
+
+        public static byte[] ToAsciiByteArray(
+            char[] cs)
+        {
+#if SILVERLIGHT || PORTABLE
+            // TODO Check for non-ASCII characters in input?
+            return Encoding.UTF8.GetBytes(cs);
+#else
+            return Encoding.ASCII.GetBytes(cs);
+#endif
+        }
+
+        public static byte[] ToAsciiByteArray(
+            string s)
+        {
+#if SILVERLIGHT || PORTABLE
+            // TODO Check for non-ASCII characters in input?
+            return Encoding.UTF8.GetBytes(s);
+#else
+            return Encoding.ASCII.GetBytes(s);
+#endif
+        }
+
+        public static string FromUtf8ByteArray(
+			byte[] bytes)
+		{
+			return Encoding.UTF8.GetString(bytes, 0, bytes.Length);
+		}
+
+        public static byte[] ToUtf8ByteArray(
+            char[] cs)
+        {
+            return Encoding.UTF8.GetBytes(cs);
+        }
+
+		public static byte[] ToUtf8ByteArray(
+			string s)
+		{
+			return Encoding.UTF8.GetBytes(s);
+		}
+	}
+}
diff --git a/Crypto/src/util/collections/CollectionUtilities.cs b/Crypto/src/util/collections/CollectionUtilities.cs
new file mode 100644
index 000000000..fd0bdcc7a
--- /dev/null
+++ b/Crypto/src/util/collections/CollectionUtilities.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections;
+using System.Text;
+
+namespace Org.BouncyCastle.Utilities.Collections
+{
+	public sealed class CollectionUtilities
+	{
+		private CollectionUtilities()
+		{
+		}
+
+        public static void AddRange(IList to, ICollection range)
+        {
+            foreach (object o in range)
+            {
+                to.Add(o);
+            }
+        }
+
+        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)
+        {
+            return new UnmodifiableDictionaryProxy(d);
+        }
+
+        public static IList ReadOnly(IList l)
+        {
+            return new UnmodifiableListProxy(l);
+        }
+
+        public static ISet ReadOnly(ISet s)
+        {
+            return new UnmodifiableSetProxy(s);
+        }
+
+        public static string ToString(
+			IEnumerable c)
+		{
+			StringBuilder sb = new StringBuilder("[");
+
+			IEnumerator e = c.GetEnumerator();
+
+			if (e.MoveNext())
+			{
+				sb.Append(e.Current.ToString());
+
+				while (e.MoveNext())
+				{
+					sb.Append(", ");
+					sb.Append(e.Current.ToString());
+				}
+			}
+
+			sb.Append(']');
+
+			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
new file mode 100644
index 000000000..5dc9fae63
--- /dev/null
+++ b/Crypto/src/util/encoders/Base64.cs
@@ -0,0 +1,95 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace Org.BouncyCastle.Utilities.Encoders
+{
+	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);
+            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,
+			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;
+		}
+
+		/**
+		 * 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);
+		}
+
+		/**
+		 * 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;
+		}
+	}
+}
diff --git a/Crypto/src/util/encoders/Base64Encoder.cs b/Crypto/src/util/encoders/Base64Encoder.cs
new file mode 100644
index 000000000..c94ce9d3c
--- /dev/null
+++ b/Crypto/src/util/encoders/Base64Encoder.cs
@@ -0,0 +1,307 @@
+using System;
+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
+//			byte[] bytes = Convert.FromBase64String(data);
+//			outStream.Write(bytes, 0, bytes.Length);
+//			return bytes.Length;
+
+			byte b1, b2, b3, b4;
+			int length = 0;
+
+			int end = data.Length;
+
+			while (end > 0)
+			{
+				if (!ignore(data[end - 1]))
+				{
+					break;
+				}
+
+				end--;
+			}
+
+			int  i = 0;
+			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));
+
+				length += 3;
+
+				i = nextI(data, i, finish);
+			}
+
+			length += decodeLastBlock(outStream, data[end - 4], data[end - 3], data[end - 2], data[end - 1]);
+
+			return length;
+		}
+
+		private int decodeLastBlock(
+			Stream	outStream,
+			char	c1,
+			char	c2,
+			char	c3,
+			char	c4)
+		{
+			if (c3 == padding)
+			{
+				byte b1 = decodingTable[c1];
+				byte b2 = decodingTable[c2];
+
+				outStream.WriteByte((byte)((b1 << 2) | (b2 >> 4)));
+
+				return 1;
+			}
+
+			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)((b2 << 4) | (b3 >> 2)));
+
+				return 2;
+			}
+
+			{
+				byte b1 = decodingTable[c1];
+				byte b2 = decodingTable[c2];
+				byte b3 = decodingTable[c3];
+				byte b4 = decodingTable[c4];
+
+				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
new file mode 100644
index 000000000..fbe475991
--- /dev/null
+++ b/Crypto/src/util/encoders/Hex.cs
@@ -0,0 +1,131 @@
+using System;
+using System.IO;
+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);
+            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);
+		}
+	}
+}
diff --git a/Crypto/src/util/encoders/HexEncoder.cs b/Crypto/src/util/encoders/HexEncoder.cs
new file mode 100644
index 000000000..c47d6219b
--- /dev/null
+++ b/Crypto/src/util/encoders/HexEncoder.cs
@@ -0,0 +1,164 @@
+using System;
+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;
+		}
+	}
+}
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
new file mode 100644
index 000000000..08eedb160
--- /dev/null
+++ b/Crypto/src/util/io/BaseInputStream.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+    public abstract class BaseInputStream : Stream
+    {
+		private bool closed;
+
+		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 sealed override long Length { get { throw new NotSupportedException(); } }
+        public sealed override long Position
+        {
+            get { throw new NotSupportedException(); }
+            set { throw new NotSupportedException(); }
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            int pos = offset;
+            try
+            {
+                int end = offset + count;
+                while (pos < end)
+                {
+                    int b = ReadByte();
+                    if (b == -1) break;
+                    buffer[pos++] = (byte) b;
+                }
+            }
+            catch (IOException)
+            {
+                if (pos == offset) throw;
+            }
+            return pos - offset;
+        }
+
+        public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+        public sealed override void SetLength(long value) { throw new NotSupportedException(); }
+        public sealed override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
+    }
+}
diff --git a/Crypto/src/util/io/BaseOutputStream.cs b/Crypto/src/util/io/BaseOutputStream.cs
new file mode 100644
index 000000000..77233f68c
--- /dev/null
+++ b/Crypto/src/util/io/BaseOutputStream.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+    public abstract class BaseOutputStream : Stream
+    {
+		private bool closed;
+
+		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 Flush() {}
+        public sealed override long Length { get { throw new NotSupportedException(); } }
+        public sealed override long Position
+        {
+            get { throw new NotSupportedException(); }
+            set { throw new NotSupportedException(); }
+        }
+        public sealed override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
+        public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+        public sealed override void SetLength(long value) { throw new NotSupportedException(); }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            Debug.Assert(buffer != null);
+            Debug.Assert(0 <= offset && offset <= buffer.Length);
+            Debug.Assert(count >= 0);
+
+            int end = offset + count;
+
+            Debug.Assert(0 <= end && end <= buffer.Length);
+
+            for (int i = offset; i < end; ++i)
+            {
+                this.WriteByte(buffer[i]);
+            }
+        }
+
+		public virtual void Write(params byte[] buffer)
+		{
+			Write(buffer, 0, buffer.Length);
+		}
+	}
+}
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
new file mode 100644
index 000000000..a8e7432fa
--- /dev/null
+++ b/Crypto/src/util/io/StreamOverflowException.cs
@@ -0,0 +1,27 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+	public class StreamOverflowException
+		: IOException
+	{
+		public StreamOverflowException()
+			: base()
+		{
+		}
+
+		public StreamOverflowException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public StreamOverflowException(
+			string		message,
+			Exception	exception)
+			: base(message, exception)
+		{
+		}
+	}
+}
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
new file mode 100644
index 000000000..fed9823f0
--- /dev/null
+++ b/Crypto/src/util/io/TeeInputStream.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+	public class TeeInputStream
+		: BaseInputStream
+	{
+		private readonly Stream input, tee;
+
+		public TeeInputStream(Stream input, Stream tee)
+		{
+			Debug.Assert(input.CanRead);
+			Debug.Assert(tee.CanWrite);
+
+			this.input = input;
+			this.tee = tee;
+		}
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                input.Dispose();
+                tee.Dispose();
+            }
+        }
+
+		public override int Read(byte[] buf, int off, int len)
+		{
+			int i = input.Read(buf, off, len);
+
+			if (i > 0)
+			{
+				tee.Write(buf, off, i);
+			}
+
+			return i;
+		}
+
+		public override int ReadByte()
+		{
+			int i = input.ReadByte();
+
+			if (i >= 0)
+			{
+				tee.WriteByte((byte)i);
+			}
+
+			return i;
+		}
+	}
+}
diff --git a/Crypto/src/util/io/TeeOutputStream.cs b/Crypto/src/util/io/TeeOutputStream.cs
new file mode 100644
index 000000000..965ef23c8
--- /dev/null
+++ b/Crypto/src/util/io/TeeOutputStream.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+    public class TeeOutputStream
+		: BaseOutputStream
+	{
+		private readonly Stream output, tee;
+
+		public TeeOutputStream(Stream output, Stream tee)
+		{
+			Debug.Assert(output.CanWrite);
+			Debug.Assert(tee.CanWrite);
+
+			this.output = output;
+			this.tee = tee;
+		}
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                output.Dispose();
+                tee.Dispose();
+            }
+        }
+
+		public override void Write(byte[] buffer, int offset, int count)
+		{
+			output.Write(buffer, offset, count);
+			tee.Write(buffer, offset, count);
+		}
+
+		public override void WriteByte(byte b)
+		{
+			output.WriteByte(b);
+			tee.WriteByte(b);
+		}
+	}
+}
diff --git a/Crypto/src/util/io/pem/PemGenerationException.cs b/Crypto/src/util/io/pem/PemGenerationException.cs
new file mode 100644
index 000000000..22e83ac2d
--- /dev/null
+++ b/Crypto/src/util/io/pem/PemGenerationException.cs
@@ -0,0 +1,26 @@
+using System;
+
+namespace Org.BouncyCastle.Utilities.IO.Pem
+{
+	public class PemGenerationException
+		: Exception
+	{
+		public PemGenerationException()
+			: base()
+		{
+		}
+
+		public PemGenerationException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public PemGenerationException(
+			string		message,
+			Exception	exception)
+			: base(message, exception)
+		{
+		}
+	}
+}
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
new file mode 100644
index 000000000..6dea74223
--- /dev/null
+++ b/Crypto/src/util/zlib/ZDeflaterOutputStream.cs
@@ -0,0 +1,155 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+    /// <summary>
+    /// Summary description for DeflaterOutputStream.
+    /// </summary>
+    [Obsolete("Use 'ZOutputStream' instead")]
+    public class ZDeflaterOutputStream : Stream {
+        protected ZStream z=new ZStream();
+        protected int flushLevel=JZlib.Z_NO_FLUSH;
+        private const int BUFSIZE = 4192;
+        protected byte[] buf=new byte[BUFSIZE];
+        private byte[] buf1=new byte[1];
+
+        protected Stream outp;
+
+        public ZDeflaterOutputStream(Stream outp) : this(outp, 6, false) {
+        }
+    
+        public ZDeflaterOutputStream(Stream outp, int level) : this(outp, level, false) {
+        }
+    
+        public ZDeflaterOutputStream(Stream outp, int level, bool nowrap) {
+            this.outp=outp;
+            z.deflateInit(level, nowrap);
+        }
+    
+    
+        public override bool CanRead {
+            get {
+                // TODO:  Add DeflaterOutputStream.CanRead getter implementation
+                return false;
+            }
+        }
+    
+        public override bool CanSeek {
+            get {
+                // TODO:  Add DeflaterOutputStream.CanSeek getter implementation
+                return false;
+            }
+        }
+    
+        public override bool CanWrite {
+            get {
+                // TODO:  Add DeflaterOutputStream.CanWrite getter implementation
+                return true;
+            }
+        }
+    
+        public override long Length {
+            get {
+                // TODO:  Add DeflaterOutputStream.Length getter implementation
+                return 0;
+            }
+        }
+    
+        public override long Position {
+            get {
+                // TODO:  Add DeflaterOutputStream.Position getter implementation
+                return 0;
+            }
+            set {
+                // TODO:  Add DeflaterOutputStream.Position setter implementation
+            }
+        }
+    
+        public override void Write(byte[] b, int off, int len) {
+            if(len==0)
+                return;
+            int err;
+            z.next_in=b;
+            z.next_in_index=off;
+            z.avail_in=len;
+            do{
+                z.next_out=buf;
+                z.next_out_index=0;
+                z.avail_out=BUFSIZE;
+                err=z.deflate(flushLevel);
+                if(err!=JZlib.Z_OK)
+                    throw new IOException("deflating: "+z.msg);
+				if (z.avail_out < BUFSIZE)
+				{
+					outp.Write(buf, 0, BUFSIZE-z.avail_out);
+				}
+            }
+            while(z.avail_in>0 || z.avail_out==0);
+        }
+    
+        public override long Seek(long offset, SeekOrigin origin) {
+            // TODO:  Add DeflaterOutputStream.Seek implementation
+            return 0;
+        }
+    
+        public override void SetLength(long value) {
+            // TODO:  Add DeflaterOutputStream.SetLength implementation
+
+        }
+    
+        public override int Read(byte[] buffer, int offset, int count) {
+            // TODO:  Add DeflaterOutputStream.Read implementation
+            return 0;
+        }
+    
+        public override void Flush() {
+            outp.Flush();
+        }
+    
+        public override void WriteByte(byte b) {
+            buf1[0]=(byte)b;
+            Write(buf1, 0, 1);
+        }
+
+        public void Finish() {
+            int err;
+            do{
+                z.next_out=buf;
+                z.next_out_index=0;
+                z.avail_out=BUFSIZE;
+                err=z.deflate(JZlib.Z_FINISH);
+                if(err!=JZlib.Z_STREAM_END && err != JZlib.Z_OK)
+                    throw new IOException("deflating: "+z.msg);
+                if(BUFSIZE-z.avail_out>0){
+                    outp.Write(buf, 0, BUFSIZE-z.avail_out);
+                }
+            }
+            while(z.avail_in>0 || z.avail_out==0);
+            Flush();
+        }
+
+        public void End() {
+            if(z==null)
+                return;
+            z.deflateEnd();
+            z.free();
+            z=null;
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                try{
+                    try { Finish(); }
+                    catch (IOException) { }
+                }
+                finally{
+                    End();
+                    outp.Dispose();
+                    outp = null;
+                }
+            }
+        }
+    }
+}
diff --git a/Crypto/src/util/zlib/ZInflaterInputStream.cs b/Crypto/src/util/zlib/ZInflaterInputStream.cs
new file mode 100644
index 000000000..d2d70ebd1
--- /dev/null
+++ b/Crypto/src/util/zlib/ZInflaterInputStream.cs
@@ -0,0 +1,131 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Zlib {
+    /// <summary>
+    /// Summary description for DeflaterOutputStream.
+    /// </summary>
+    [Obsolete("Use 'ZInputStream' instead")]
+    public class ZInflaterInputStream : Stream {
+        protected ZStream z=new ZStream();
+        protected int flushLevel=JZlib.Z_NO_FLUSH;
+        private const int BUFSIZE = 4192;
+        protected byte[] buf=new byte[BUFSIZE];
+        private byte[] buf1=new byte[1];
+
+        protected Stream inp=null;
+        private bool nomoreinput=false;
+
+        public ZInflaterInputStream(Stream inp) : this(inp, false) {
+        }
+    
+        public ZInflaterInputStream(Stream inp, bool nowrap) {
+            this.inp=inp;
+            z.inflateInit(nowrap);
+            z.next_in=buf;
+            z.next_in_index=0;
+            z.avail_in=0;
+        }
+    
+        public override bool CanRead {
+            get {
+                // TODO:  Add DeflaterOutputStream.CanRead getter implementation
+                return true;
+            }
+        }
+    
+        public override bool CanSeek {
+            get {
+                // TODO:  Add DeflaterOutputStream.CanSeek getter implementation
+                return false;
+            }
+        }
+    
+        public override bool CanWrite {
+            get {
+                // TODO:  Add DeflaterOutputStream.CanWrite getter implementation
+                return false;
+            }
+        }
+    
+        public override long Length {
+            get {
+                // TODO:  Add DeflaterOutputStream.Length getter implementation
+                return 0;
+            }
+        }
+    
+        public override long Position {
+            get {
+                // TODO:  Add DeflaterOutputStream.Position getter implementation
+                return 0;
+            }
+            set {
+                // TODO:  Add DeflaterOutputStream.Position setter implementation
+            }
+        }
+    
+        public override void Write(byte[] b, int off, int len) {
+        }
+    
+        public override long Seek(long offset, SeekOrigin origin) {
+            // TODO:  Add DeflaterOutputStream.Seek implementation
+            return 0;
+        }
+    
+        public override void SetLength(long value) {
+            // TODO:  Add DeflaterOutputStream.SetLength implementation
+
+        }
+    
+        public override int Read(byte[] b, int off, int len) {
+            if(len==0)
+                return(0);
+            int err;
+            z.next_out=b;
+            z.next_out_index=off;
+            z.avail_out=len;
+            do {
+                if((z.avail_in==0)&&(!nomoreinput)) { // if buffer is empty and more input is avaiable, refill it
+                    z.next_in_index=0;
+                    z.avail_in=inp.Read(buf, 0, BUFSIZE);//(BUFSIZE<z.avail_out ? BUFSIZE : z.avail_out));
+                    if(z.avail_in<=0) {
+                        z.avail_in=0;
+                        nomoreinput=true;
+                    }
+                }
+                err=z.inflate(flushLevel);
+                if(nomoreinput&&(err==JZlib.Z_BUF_ERROR))
+                    return(0);
+                if(err!=JZlib.Z_OK && err!=JZlib.Z_STREAM_END)
+                    throw new IOException("inflating: "+z.msg);
+                if((nomoreinput||err==JZlib.Z_STREAM_END)&&(z.avail_out==len))
+                    return(0);
+            } 
+            while(z.avail_out==len&&err==JZlib.Z_OK);
+            //System.err.print("("+(len-z.avail_out)+")");
+            return(len-z.avail_out);
+        }
+    
+        public override void Flush() {
+            inp.Flush();
+        }
+    
+        public override void WriteByte(byte b) {
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                inp.Dispose();
+            }
+        }
+    
+        public override int ReadByte() {
+            if(Read(buf1, 0, 1)<=0)
+                return -1;
+            return(buf1[0]&0xFF);
+        }
+    }
+}
diff --git a/Crypto/src/util/zlib/ZInputStream.cs b/Crypto/src/util/zlib/ZInputStream.cs
new file mode 100644
index 000000000..179c133bf
--- /dev/null
+++ b/Crypto/src/util/zlib/ZInputStream.cs
@@ -0,0 +1,196 @@
+/*
+Copyright (c) 2001 Lapo Luchini.
+
+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 THE AUTHORS
+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.
+ */
+/* This file is a port of jzlib v1.0.7, com.jcraft.jzlib.ZInputStream.java
+ */
+
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Zlib
+{
+	public class ZInputStream
+		: Stream
+	{
+		private const int BufferSize = 512;
+
+		protected ZStream z = new ZStream();
+		protected int flushLevel = JZlib.Z_NO_FLUSH;
+		// TODO Allow custom buf
+		protected byte[] buf = new byte[BufferSize];
+		protected byte[] buf1 = new byte[1];
+		protected bool compress;
+
+		protected Stream input;
+		protected bool closed;
+
+		private bool nomoreinput = false;
+
+		public ZInputStream(Stream input)
+			: this(input, false)
+		{
+		}
+
+		public ZInputStream(Stream input, bool nowrap)
+		{
+			Debug.Assert(input.CanRead);
+
+			this.input = input;
+			this.z.inflateInit(nowrap);
+			this.compress = false;
+			this.z.next_in = buf;
+			this.z.next_in_index = 0;
+			this.z.avail_in = 0;
+		}
+
+		public ZInputStream(Stream input, int level)
+		{
+			Debug.Assert(input.CanRead);
+			
+			this.input = input;
+			this.z.deflateInit(level);
+			this.compress = true;
+			this.z.next_in = buf;
+			this.z.next_in_index = 0;
+			this.z.avail_in = 0;
+		}
+
+		/*public int available() throws IOException {
+		return inf.finished() ? 0 : 1;
+		}*/
+
+		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)
+        {
+            if (disposing)
+            {
+                if (!closed)
+                {
+                    closed = true;
+                    input.Dispose();
+                }
+            }
+		}
+
+		public sealed override void Flush() {}
+
+		public virtual int FlushMode
+		{
+			get { return flushLevel; }
+			set { this.flushLevel = value; }
+		}
+
+		public sealed override long Length { get { throw new NotSupportedException(); } }
+		public sealed override long Position
+		{
+			get { throw new NotSupportedException(); }
+			set { throw new NotSupportedException(); }
+		}
+
+		public override int Read(byte[]	b, int off, int len)
+		{
+			if (len==0)
+				return 0;
+
+			z.next_out = b;
+			z.next_out_index = off;
+			z.avail_out = len;
+
+			int err;
+			do
+			{
+				if (z.avail_in == 0 && !nomoreinput)
+				{
+					// if buffer is empty and more input is available, refill it
+					z.next_in_index = 0;
+					z.avail_in = input.Read(buf, 0, buf.Length); //(bufsize<z.avail_out ? bufsize : z.avail_out));
+
+					if (z.avail_in <= 0)
+					{
+						z.avail_in = 0;
+						nomoreinput = true;
+					}
+				}
+
+				err = compress
+					?	z.deflate(flushLevel)
+					:	z.inflate(flushLevel);
+
+				if (nomoreinput && err == JZlib.Z_BUF_ERROR)
+					return 0;
+				if (err != JZlib.Z_OK && err != JZlib.Z_STREAM_END)
+					// TODO
+//					throw new ZStreamException((compress ? "de" : "in") + "flating: " + z.msg);
+					throw new IOException((compress ? "de" : "in") + "flating: " + z.msg);
+				if ((nomoreinput || err == JZlib.Z_STREAM_END) && z.avail_out == len)
+					return 0;
+			} 
+			while(z.avail_out == len && err == JZlib.Z_OK);
+			//Console.Error.WriteLine("("+(len-z.avail_out)+")");
+			return len - z.avail_out;
+		}
+
+		public override int ReadByte()
+		{
+			if (Read(buf1, 0, 1) <= 0)
+				return -1;
+			return buf1[0];
+		}
+
+//  public long skip(long n) throws IOException {
+//    int len=512;
+//    if(n<len)
+//      len=(int)n;
+//    byte[] tmp=new byte[len];
+//    return((long)read(tmp));
+//  }
+
+		public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+		public sealed override void SetLength(long value) { throw new NotSupportedException(); }
+
+		public virtual long TotalIn
+		{
+			get { return z.total_in; }
+		}
+
+		public virtual long TotalOut
+		{
+			get { return z.total_out; }
+		}
+
+		public sealed override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
+	}
+}
diff --git a/Crypto/src/util/zlib/ZOutputStream.cs b/Crypto/src/util/zlib/ZOutputStream.cs
new file mode 100644
index 000000000..7ea7cbb33
--- /dev/null
+++ b/Crypto/src/util/zlib/ZOutputStream.cs
@@ -0,0 +1,220 @@
+/*
+Copyright (c) 2001 Lapo Luchini.
+
+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 THE AUTHORS
+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.
+ */
+/* This file is a port of jzlib v1.0.7, com.jcraft.jzlib.ZOutputStream.java
+ */
+
+using System;
+using System.Diagnostics;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.Zlib
+{
+	public class ZOutputStream
+		: Stream
+	{
+		private const int BufferSize = 512;
+
+		protected ZStream z = new ZStream();
+		protected int flushLevel = JZlib.Z_NO_FLUSH;
+		// TODO Allow custom buf
+		protected byte[] buf = new byte[BufferSize];
+		protected byte[] buf1 = new byte[1];
+		protected bool compress;
+
+		protected Stream output;
+		protected bool closed;
+
+		public ZOutputStream(Stream output)
+			: base()
+		{
+			Debug.Assert(output.CanWrite);
+
+			this.output = output;
+			this.z.inflateInit();
+			this.compress = false;
+		}
+
+		public ZOutputStream(Stream output, int level)
+			: this(output, level, false)
+		{
+		}
+
+		public ZOutputStream(Stream output, int level, bool nowrap)
+			: base()
+		{
+			Debug.Assert(output.CanWrite);
+
+			this.output = output;
+			this.z.deflateInit(level, nowrap);
+			this.compress = true;
+		}
+
+		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)
+        {
+            if (disposing)
+            {
+                if (this.closed)
+                    return;
+
+                try
+                {
+                    try
+                    {
+                        Finish();
+                    }
+                    catch (IOException)
+                    {
+                        // Ignore
+                    }
+                }
+                finally
+                {
+                    this.closed = true;
+                    End();
+                    output.Dispose();
+                    output = null;
+                }
+            }
+		}
+
+		public virtual void End()
+		{
+			if (z == null)
+				return;
+			if (compress)
+				z.deflateEnd();
+			else
+				z.inflateEnd();
+			z.free();
+			z = null;
+		}
+
+		public virtual void Finish()
+		{
+			do
+			{
+				z.next_out = buf;
+				z.next_out_index = 0;
+				z.avail_out = buf.Length;
+
+				int err = compress
+					?	z.deflate(JZlib.Z_FINISH)
+					:	z.inflate(JZlib.Z_FINISH);
+
+				if (err != JZlib.Z_STREAM_END && err != JZlib.Z_OK)
+					// TODO
+//					throw new ZStreamException((compress?"de":"in")+"flating: "+z.msg);
+					throw new IOException((compress ? "de" : "in") + "flating: " + z.msg);
+
+				int count = buf.Length - z.avail_out;
+				if (count > 0)
+				{
+					output.Write(buf, 0, count);
+				}
+			}
+			while (z.avail_in > 0 || z.avail_out == 0);
+
+			Flush();
+		}
+
+		public override void Flush()
+		{
+			output.Flush();
+		}
+
+		public virtual int FlushMode
+		{
+			get { return flushLevel; }
+			set { this.flushLevel = value; }
+		}
+
+        public sealed override long Length { get { throw new NotSupportedException(); } }
+        public sealed override long Position
+        {
+            get { throw new NotSupportedException(); }
+            set { throw new NotSupportedException(); }
+        }
+        public sealed override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
+        public sealed override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
+        public sealed override void SetLength(long value) { throw new NotSupportedException(); }
+
+		public virtual long TotalIn
+		{
+			get { return z.total_in; }
+		}
+
+		public virtual long TotalOut
+		{
+			get { return z.total_out; }
+		}
+
+		public override void Write(byte[] b, int off, int len)
+		{
+			if (len == 0)
+				return;
+
+			z.next_in = b;
+			z.next_in_index = off;
+			z.avail_in = len;
+
+			do
+			{
+				z.next_out = buf;
+				z.next_out_index = 0;
+				z.avail_out = buf.Length;
+
+				int err = compress
+					?	z.deflate(flushLevel)
+					:	z.inflate(flushLevel);
+
+				if (err != JZlib.Z_OK)
+					// TODO
+//					throw new ZStreamException((compress ? "de" : "in") + "flating: " + z.msg);
+					throw new IOException((compress ? "de" : "in") + "flating: " + z.msg);
+
+				output.Write(buf, 0, buf.Length - z.avail_out);
+			}
+			while (z.avail_in > 0 || z.avail_out == 0);
+		}
+
+		public override void WriteByte(byte b)
+		{
+			buf1[0] = b;
+			Write(buf1, 0, 1);
+		}
+	}
+}
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
new file mode 100644
index 000000000..54ca78090
--- /dev/null
+++ b/Crypto/src/x509/SubjectPublicKeyInfoFactory.cs
@@ -0,0 +1,187 @@
+using System;
+using System.IO;
+using System.Collections;
+using System.Text;
+
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.X509
+{
+    /// <summary>
+    /// A factory to produce Public Key Info Objects.
+    /// </summary>
+    public sealed class SubjectPublicKeyInfoFactory
+    {
+        private SubjectPublicKeyInfoFactory()
+        {
+        }
+
+		/// <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)
+        {
+			if (key == null)
+				throw new ArgumentNullException("key");
+            if (key.IsPrivate)
+                throw new ArgumentException("Private key passed - public key expected.", "key");
+
+			if (key is ElGamalPublicKeyParameters)
+            {
+				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));
+
+				return info;
+            }
+
+			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();
+
+				return new SubjectPublicKeyInfo(
+                    new AlgorithmIdentifier(X9ObjectIdentifiers.IdDsa, ae),
+					new DerInteger(_key.Y));
+            }
+
+			if (key is DHPublicKeyParameters)
+            {
+                DHPublicKeyParameters _key = (DHPublicKeyParameters) key;
+				DHParameters kp = _key.Parameters;
+
+				SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(
+                    new AlgorithmIdentifier(
+						_key.AlgorithmOid,
+						new DHParameter(kp.P, kp.G, kp.L).ToAsn1Object()),
+						new DerInteger(_key.Y));
+
+				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());
+
+				return info;
+            } // End of RSA.
+
+			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];
+			}
+		}
+	}
+}
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
new file mode 100644
index 000000000..000958340
--- /dev/null
+++ b/Crypto/src/x509/X509Utilities.cs
@@ -0,0 +1,188 @@
+using System;
+using System.Collections;
+using System.Globalization;
+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.Asn1.X9;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.X509
+{
+	internal class X509Utilities
+	{
+        private static readonly IDictionary algorithms = Platform.CreateHashtable();
+        private static readonly IDictionary exParams = Platform.CreateHashtable();
+		private static readonly ISet        noParams = new HashSet();
+
+		static X509Utilities()
+		{
+			algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+			algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+			algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+			algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+			algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+			algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+			algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+			algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+			algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+			algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+			algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+			algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+			algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+			algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+			algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+			algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+			algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+			algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+			algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+			algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+			algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1);
+			algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1);
+			algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+			algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+			algorithms.Add("SHA384WITHDSA", NistObjectIdentifiers.DsaWithSha384);
+			algorithms.Add("SHA512WITHDSA", NistObjectIdentifiers.DsaWithSha512);
+			algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+			algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+			algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+			algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+			algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+			algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+			algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+			algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+			algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+			algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+			algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+			//
+			// According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+			// The parameters field SHALL be NULL for RSA based signature algorithms.
+			//
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+			noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+			noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+			noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+			noParams.Add(NistObjectIdentifiers.DsaWithSha384);
+			noParams.Add(NistObjectIdentifiers.DsaWithSha512);
+
+			//
+			// RFC 4491
+			//
+			noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+			noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+			//
+			// explicit params
+			//
+			AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+			exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20));
+
+			AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance);
+			exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28));
+
+			AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance);
+			exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32));
+
+			AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance);
+			exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48));
+
+			AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance);
+			exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64));
+		}
+
+		private static RsassaPssParameters CreatePssParams(
+			AlgorithmIdentifier	hashAlgId,
+			int					saltSize)
+		{
+			return new RsassaPssParameters(
+				hashAlgId,
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId),
+				new DerInteger(saltSize),
+				new DerInteger(1));
+		}
+
+		internal static DerObjectIdentifier GetAlgorithmOid(
+			string algorithmName)
+		{
+			algorithmName = algorithmName.ToUpperInvariant();
+
+			if (algorithms.Contains(algorithmName))
+			{
+				return (DerObjectIdentifier) algorithms[algorithmName];
+			}
+
+			return new DerObjectIdentifier(algorithmName);
+		}
+
+		internal static AlgorithmIdentifier GetSigAlgID(
+			DerObjectIdentifier sigOid,
+			string				algorithmName)
+		{
+			if (noParams.Contains(sigOid))
+			{
+				return new AlgorithmIdentifier(sigOid);
+			}
+
+			algorithmName = algorithmName.ToUpperInvariant();
+
+			if (exParams.Contains(algorithmName))
+			{
+				return new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
+			}
+
+			return new AlgorithmIdentifier(sigOid, DerNull.Instance);
+		}
+
+		internal static IEnumerable GetAlgNames()
+		{
+			return new EnumerableProxy(algorithms.Keys);
+		}
+
+		internal static byte[] GetSignatureForObject(
+			DerObjectIdentifier		sigOid, // TODO Redundant now?
+			string					sigName,
+			AsymmetricKeyParameter	privateKey,
+			SecureRandom			random,
+			Asn1Encodable			ae)
+		{
+			if (sigOid == null)
+				throw new ArgumentNullException("sigOid");
+
+			ISigner sig = SignerUtilities.GetSigner(sigName);
+
+			if (random != null)
+			{
+				sig.Init(true, new ParametersWithRandom(privateKey, random));
+			}
+			else
+			{
+				sig.Init(true, privateKey);
+			}
+
+			byte[] encoded = ae.GetDerEncoded();
+			sig.BlockUpdate(encoded, 0, encoded.Length);
+
+			return sig.GenerateSignature();
+		}
+	}
+}
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
new file mode 100644
index 000000000..3f37fcd66
--- /dev/null
+++ b/Crypto/src/x509/store/IX509Selector.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+	public interface IX509Selector
+#if !(SILVERLIGHT || PORTABLE)
+		: ICloneable
+#endif
+    {
+#if SILVERLIGHT || PORTABLE
+        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
new file mode 100644
index 000000000..3df26de79
--- /dev/null
+++ b/Crypto/src/x509/store/NoSuchStoreException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+	public class NoSuchStoreException
+		: X509StoreException
+	{
+		public NoSuchStoreException()
+		{
+		}
+
+		public NoSuchStoreException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public NoSuchStoreException(
+			string		message,
+			Exception	e)
+			: base(message, e)
+		{
+		}
+	}
+}
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
new file mode 100644
index 000000000..f6a5e235f
--- /dev/null
+++ b/Crypto/src/x509/store/X509StoreException.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace Org.BouncyCastle.X509.Store
+{
+	public class X509StoreException
+		: Exception
+	{
+		public X509StoreException()
+		{
+		}
+
+		public X509StoreException(
+			string message)
+			: base(message)
+		{
+		}
+
+		public X509StoreException(
+			string		message,
+			Exception	e)
+			: base(message, e)
+		{
+		}
+	}
+}
diff --git a/Crypto/src/x509/store/X509StoreFactory.cs b/Crypto/src/x509/store/X509StoreFactory.cs
new file mode 100644
index 000000000..322639991
--- /dev/null
+++ b/Crypto/src/x509/store/X509StoreFactory.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections;
+using System.Globalization;
+
+namespace Org.BouncyCastle.X509.Store
+{
+	public sealed class X509StoreFactory
+	{
+		private X509StoreFactory()
+		{
+		}
+
+		public static IX509Store Create(
+			string					type,
+			IX509StoreParameters	parameters)
+		{
+			if (type == null)
+				throw new ArgumentNullException("type");
+
+			string[] parts = type.ToUpperInvariant().Split('/');
+
+			if (parts.Length < 2)
+				throw new ArgumentException("type");
+
+			if (parts[1] != "COLLECTION")
+				throw new NoSuchStoreException("X.509 store type '" + type + "' not available.");
+
+			X509CollectionStoreParameters p = (X509CollectionStoreParameters) parameters;
+			ICollection coll = p.GetCollection();
+
+			switch (parts[0])
+			{
+				case "ATTRIBUTECERTIFICATE":
+					checkCorrectType(coll, typeof(IX509AttributeCertificate));
+					break;
+				case "CERTIFICATE":
+					checkCorrectType(coll, typeof(X509Certificate));
+					break;
+				case "CERTIFICATEPAIR":
+					checkCorrectType(coll, typeof(X509CertificatePair));
+					break;
+				case "CRL":
+					checkCorrectType(coll, typeof(X509Crl));
+					break;
+				default:
+					throw new NoSuchStoreException("X.509 store type '" + type + "' not available.");
+			}
+
+			return new X509CollectionStore(coll);
+		}
+
+		private static void checkCorrectType(ICollection coll, Type t)
+		{
+			foreach (object o in coll)
+			{
+				if (!t.IsInstanceOfType(o))
+					throw new InvalidCastException("Can't cast object to type: " + t.FullName);
+			}
+		}
+	}
+}
diff --git a/License.html b/License.html
new file mode 100644
index 000000000..0dae3a978
--- /dev/null
+++ b/License.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+  <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+  <title>License</title>
+</head>
+<body>
+<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
+(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
+Software without restriction, including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sub license, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:<br>
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.<br>
+<span style="font-weight: bold;">THE SOFTWARE IS PROVIDED "AS IS",
+WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">INCLUDING BUT NOT LIMITED TO THE
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">PURPOSE AND NONINFRINGEMENT. IN NO
+EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER</span><br
+ style="font-weight: bold;">
+<span style="font-weight: bold;">DEALINGS IN THE SOFTWARE.<br>
+<br>
+</span>
+</body>
+</html>
diff --git a/Portable.BouncyCastle.nuspec b/Portable.BouncyCastle.nuspec
new file mode 100644
index 000000000..8de911a3b
--- /dev/null
+++ b/Portable.BouncyCastle.nuspec
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
+    <metadata>
+        <id>Portable.BouncyCastle</id>
+        <version>1.7.0</version>
+        <title>Bouncy Castle PCL</title>
+        <authors>Oren Novotny</authors>
+        <owners>onovotny</owners>
+        <projectUrl>https://github.com/onovotny/BouncyCastle-PCL</projectUrl>
+        <requireLicenseAcceptance>false</requireLicenseAcceptance>
+        <description>BouncyCastle.Crypto is a cryptography API providing:
+ -Generation and parsing of PKCS#12 files.
+ -X.509: Generators and parsers for V1 and V3 certificates, V2 CRLs and attribute certificates.
+ -PBE algorithms supported by PBEUtil: PBEwithMD2andDES-CBC, PBEwithMD2andRC2-CBC, PBEwithMD5andDES-CBC, PBEwithMD5andRC2-CBC, PBEwithSHA1andDES-CBC, PBEwithSHA1andRC2-CBC, PBEwithSHA-1and128bitRC4, PBEwithSHA-1and40bitRC4, PBEwithSHA-1and3-keyDESEDE-CBC, PBEwithSHA-1and2-keyDESEDE-CBC, PBEwithSHA-1and128bitRC2-CBC, PBEwithSHA-1and40bitRC2-CBC, PBEwithHmacSHA-1, PBEwithHmacSHA-224, PBEwithHmacSHA-256, PBEwithHmacRIPEMD128, PBEwithHmacRIPEMD160, and PBEwithHmacRIPEMD256.
+ -Signature algorithms supported by SignerUtilities: MD2withRSA, MD4withRSA, MD5withRSA, RIPEMD128withRSA, RIPEMD160withRSA, RIPEMD256withRSA, SHA-1withRSA, SHA-224withRSA, SHA-256withRSAandMGF1, SHA-384withRSAandMGF1, SHA-512withRSAandMGF1, SHA-1withDSA, and SHA-1withECDSA.
+ -Symmetric key algorithms: AES, Blowfish, Camellia, CAST5, CAST6, DESede, DES, GOST28147, HC-128, HC-256, IDEA, NaccacheStern, RC2, RC4, RC5-32, RC5-64, RC6, Rijndael, Serpent, Skipjack, TEA/XTEA, Twofish, and VMPC.
+ -Symmetric key modes: CBC, CFB, CTS, GOFB, OFB, OpenPGPCFB, and SIC (or CTR).
+ -Symmetric key paddings: ISO10126d2, ISO7816d4, PKCS#5/7, TBC, X.923, and Zero Byte.
+ -Asymmetric key algorithms: RSA (with blinding), ElGamal, DSA, ECDSA.
+ -Asymmetric key paddings/encodings: ISO9796d1, OAEP, and PKCS#1.
+ -Digests: GOST3411, MD2, MD4, MD5, RIPEMD128, RIPEMD160, RIPEMD256, RIPEMD320, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, Tiger, and Whirlpool.
+ -Signer mechanisms: DSA, ECDSA, ECGOST3410, GOST3410, ISO9796d2, PSS, RSA.
+ -Key Agreement: Diffie-Hellman and EC-DH.
+ -Macs: CBCBlockCipher, CFBBlockCipher, GOST28147, HMac, and ISO9797 Alg. 3.
+ -PBE generators: PKCS#12, and PKCS#5 - schemes 1 and 2.
+ -OpenPGP (RFC 2440)
+ -Cryptographic Message Syntax (CMS, RFC 3852), including streaming API.
+ -Online Certificate Status Protocol (OCSP, RFC 2560).
+ -Time Stamp Protocol (TSP, RFC 3161).
+ -TLS/SSL Client with support for client side authentication.</description>
+        <language>en-US</language>
+        <tags>bouncycastle, cryptography, encryption, security, PCL</tags>
+    </metadata>
+    <files>
+        <file src="Crypto\bin\Release\crypto.xml" target="lib\portable-net4+sl5+wp8+win8\crypto.xml" />
+        <file src="Crypto\bin\Release\crypto.pdb" target="lib\portable-net4+sl5+wp8+win8\crypto.pdb" />
+        <file src="Crypto\bin\Release\crypto.dll" target="lib\portable-net4+sl5+wp8+win8\crypto.dll" />
+        <file src="Crypto\Readme.html" target="Readme.html" />
+        <file src="**\*.cs" target="src" exclude="_ReSharper.*\**\*.*;packages\**\*.*;**\Debug\**\*.*;" />
+    </files>
+</package>
\ No newline at end of file
diff --git a/pack.cmd b/pack.cmd
new file mode 100644
index 000000000..0a0605ea0
--- /dev/null
+++ b/pack.cmd
@@ -0,0 +1 @@
+.nuget\nuget.exe pack Portable.BouncyCastle.nuspec -Symbols
\ No newline at end of file