summary refs log tree commit diff
diff options
context:
space:
mode:
authorMW <megan@cryptoworkshop.com>2019-01-17 16:16:20 +1100
committerMW <megan@cryptoworkshop.com>2019-01-17 16:16:20 +1100
commit3d578b981aad94eaee07fa444dd11f9323026e94 (patch)
treed64141ae1163cafb69a4e3fc26ab90b538d98ef6
parentMissing from previous commit (diff)
downloadBouncyCastle.NET-ed25519-3d578b981aad94eaee07fa444dd11f9323026e94.tar.xz
CMS ArchiveControl
-rw-r--r--crypto/src/asn1/misc/MiscObjectIdentifiers.cs2
-rw-r--r--crypto/src/cmp/RevocationDetails.cs39
-rw-r--r--crypto/src/cmp/RevocationDetailsBuilder.cs58
-rw-r--r--crypto/src/cms/CMSEnvelopedDataGenerator.cs71
-rw-r--r--crypto/src/cms/CMSEnvelopedGenerator.cs10
-rw-r--r--crypto/src/cms/CMSProcessableByteArray.cs17
-rw-r--r--crypto/src/cms/EnvelopedDataHelper.cs123
-rw-r--r--crypto/src/cms/RecipientInfoGenerator.cs2
-rw-r--r--crypto/src/crmf/CertificateRequestMessage.cs4
-rw-r--r--crypto/src/crmf/CertificateRequestMessageBuilder.cs9
-rw-r--r--crypto/src/crmf/PKIArchiveControlBuilder.cs61
-rw-r--r--crypto/src/crypto/operators/Asn1Signature.cs4
-rw-r--r--crypto/src/crypto/operators/CipherFactory.cs146
-rw-r--r--crypto/src/crypto/operators/CmsContentEncryptorBuilder.cs155
-rw-r--r--crypto/src/crypto/util/AlgorithmIdentifierFactory.cs105
-rw-r--r--crypto/src/crypto/util/CipherKeyGeneratorFactory.cs101
-rw-r--r--crypto/test/src/crmf/test/CrmfTest.cs191
17 files changed, 1091 insertions, 7 deletions
diff --git a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
index d344393dd..1ff19e737 100644
--- a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
+++ b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
@@ -50,6 +50,8 @@ namespace Org.BouncyCastle.Asn1.Misc
         public static readonly string				Entrust					= "1.2.840.113533.7";
         public static readonly DerObjectIdentifier EntrustVersionExtension = new DerObjectIdentifier(Entrust + ".65.0");
 
+        public static readonly DerObjectIdentifier cast5CBC = new DerObjectIdentifier(Entrust+ ".66.10");
+
         //
         // Ascom
         //
diff --git a/crypto/src/cmp/RevocationDetails.cs b/crypto/src/cmp/RevocationDetails.cs
new file mode 100644
index 000000000..6e1cb34c3
--- /dev/null
+++ b/crypto/src/cmp/RevocationDetails.cs
@@ -0,0 +1,39 @@
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Cmp
+{
+    public class RevocationDetails
+    {
+        private RevDetails revDetails;
+
+        public RevocationDetails(RevDetails revDetails)
+        {
+            this.revDetails = revDetails;
+        }
+
+        public X509Name Subject
+        {
+            get { return revDetails.CertDetails.Subject; }
+        }
+
+        public X509Name Issuer
+        {
+            get { return revDetails.CertDetails.Issuer; }
+        }
+
+        public BigInteger SerialNumber
+        {
+            get
+            {
+                return revDetails.CertDetails.SerialNumber.Value; //   getCertDetails().getSerialNumber().getValue();
+            }
+        }
+
+        public RevDetails ToASN1Structure()
+        {
+            return revDetails;
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/cmp/RevocationDetailsBuilder.cs b/crypto/src/cmp/RevocationDetailsBuilder.cs
new file mode 100644
index 000000000..464c0bb13
--- /dev/null
+++ b/crypto/src/cmp/RevocationDetailsBuilder.cs
@@ -0,0 +1,58 @@
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Math;
+
+namespace Org.BouncyCastle.Cmp
+{
+    public class RevocationDetailsBuilder
+    {
+        private readonly CertTemplateBuilder _templateBuilder = new CertTemplateBuilder();
+
+        public RevocationDetailsBuilder SetPublicKey(SubjectPublicKeyInfo publicKey)
+        {
+            if (publicKey != null)
+            {
+                _templateBuilder.SetPublicKey(publicKey);
+            }
+
+            return this;
+        }
+
+        public RevocationDetailsBuilder SetIssuer(X509Name issuer)
+        {
+            if (issuer != null)
+            {
+                _templateBuilder.SetIssuer(issuer);
+            }
+
+            return this;
+        }
+
+        public RevocationDetailsBuilder SetSerialNumber(BigInteger serialNumber)
+        {
+            if (serialNumber != null)
+            {
+                _templateBuilder.SetSerialNumber(new DerInteger(serialNumber));
+            }
+
+            return this;
+        }
+
+        public RevocationDetailsBuilder SetSubject(X509Name subject)
+        {
+            if (subject != null)
+            {
+                _templateBuilder.SetSubject(subject);
+            }
+
+            return this;
+        }
+
+        public RevocationDetails build()
+        {
+            return new RevocationDetails(new RevDetails(_templateBuilder.Build()));
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/cms/CMSEnvelopedDataGenerator.cs b/crypto/src/cms/CMSEnvelopedDataGenerator.cs
index d260e998a..8ba41161e 100644
--- a/crypto/src/cms/CMSEnvelopedDataGenerator.cs
+++ b/crypto/src/cms/CMSEnvelopedDataGenerator.cs
@@ -144,7 +144,7 @@ namespace Org.BouncyCastle.Cms
             try
             {
 				CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
-
+               
 				keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
 
 				return Generate(content, encryptionOid, keyGen);
@@ -155,6 +155,75 @@ namespace Org.BouncyCastle.Cms
             }
         }
 
+
+        public CmsEnvelopedData Generate(CmsProcessable content, ICipherBuilderWithKey cipherBuilder)
+        {
+            AlgorithmIdentifier encAlgId = null;
+            KeyParameter encKey;
+            Asn1OctetString encContent;
+
+            try
+            {
+                encKey = (KeyParameter) cipherBuilder.Key;
+
+                MemoryStream collector = new MemoryStream();
+                Stream bOut = cipherBuilder.BuildCipher(collector).Stream;            
+                content.Write(bOut);  
+                Platform.Dispose(bOut);                            
+                encContent = new BerOctetString(collector.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,
+                (AlgorithmIdentifier) cipherBuilder.AlgorithmDetails,
+                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,
diff --git a/crypto/src/cms/CMSEnvelopedGenerator.cs b/crypto/src/cms/CMSEnvelopedGenerator.cs
index f92ae3824..ed7e1edee 100644
--- a/crypto/src/cms/CMSEnvelopedGenerator.cs
+++ b/crypto/src/cms/CMSEnvelopedGenerator.cs
@@ -263,6 +263,16 @@ namespace Org.BouncyCastle.Cms
 			recipientInfoGenerators.Add(karig);
 		}
 
+        /// <summary>
+        /// Add a generator to produce the recipient info required.
+        /// </summary>
+        /// <param name="recipientInfoGenerator">a generator of a recipient info object.</param>
+	    public void AddRecipientInfoGenerator(RecipientInfoGenerator recipientInfoGenerator)
+	    {
+	        recipientInfoGenerators.Add(recipientInfoGenerator);
+	    }
+
+
         protected internal virtual AlgorithmIdentifier GetAlgorithmIdentifier(
 			string					encryptionOid,
 			KeyParameter			encKey,
diff --git a/crypto/src/cms/CMSProcessableByteArray.cs b/crypto/src/cms/CMSProcessableByteArray.cs
index a6ab9b6a2..b09935dd8 100644
--- a/crypto/src/cms/CMSProcessableByteArray.cs
+++ b/crypto/src/cms/CMSProcessableByteArray.cs
@@ -1,5 +1,7 @@
 using System;
 using System.IO;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
 
 namespace Org.BouncyCastle.Cms
 {
@@ -9,13 +11,26 @@ namespace Org.BouncyCastle.Cms
 	public class CmsProcessableByteArray
 		: CmsProcessable, CmsReadable
 	{
+	    private readonly DerObjectIdentifier type;
 		private readonly byte[] bytes;
 
         public CmsProcessableByteArray(byte[] bytes)
-		{
+        {
+            type = CmsObjectIdentifiers.Data;
 			this.bytes = bytes;
 		}
 
+	    public CmsProcessableByteArray(DerObjectIdentifier type, byte[] bytes)
+	    {
+	        this.bytes = bytes;
+	        this.type = type;
+	    }
+
+	    public DerObjectIdentifier Type
+	    {
+	        get { return type; }
+	    }
+
         public virtual Stream GetInputStream()
 		{
 			return new MemoryStream(bytes, false);
diff --git a/crypto/src/cms/EnvelopedDataHelper.cs b/crypto/src/cms/EnvelopedDataHelper.cs
new file mode 100644
index 000000000..89ec79691
--- /dev/null
+++ b/crypto/src/cms/EnvelopedDataHelper.cs
@@ -0,0 +1,123 @@
+using System.Collections;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Cms
+{
+    public class EnvelopedDataHelper
+    {
+        private static readonly IDictionary BaseCipherNames = Platform.CreateHashtable();
+        private static readonly IDictionary MacAlgNames = Platform.CreateHashtable();
+
+        private static readonly IDictionary prfs = Platform.CreateHashtable();
+
+
+        public delegate IDigest DigestCreator();
+
+        static EnvelopedDataHelper()
+        {
+            prfs.Add(PkcsObjectIdentifiers.IdHmacWithSha1, new DigestProvider(delegate () { return new Sha1Digest(); }));
+            prfs.Add(PkcsObjectIdentifiers.IdHmacWithSha224, new DigestProvider(delegate () { return new Sha224Digest(); }));
+            prfs.Add(PkcsObjectIdentifiers.IdHmacWithSha256, new DigestProvider(delegate () { return new Sha256Digest(); }));
+            prfs.Add(PkcsObjectIdentifiers.IdHmacWithSha384, new DigestProvider(delegate () { return new Sha384Digest(); }));
+            prfs.Add(PkcsObjectIdentifiers.IdHmacWithSha512, new DigestProvider(delegate () { return new Sha512Digest(); }));
+
+
+            BaseCipherNames.Add(PkcsObjectIdentifiers.DesEde3Cbc, "DESEDE");
+            BaseCipherNames.Add(NistObjectIdentifiers.IdAes128Cbc, "AES");
+            BaseCipherNames.Add(NistObjectIdentifiers.IdAes192Cbc, "AES");
+            BaseCipherNames.Add(NistObjectIdentifiers.IdAes256Cbc, "AES");
+
+            MacAlgNames.Add(PkcsObjectIdentifiers.DesEde3Cbc, "DESEDEMac");
+            MacAlgNames.Add(NistObjectIdentifiers.IdAes128Cbc, "AESMac");
+            MacAlgNames.Add(NistObjectIdentifiers.IdAes192Cbc, "AESMac");
+            MacAlgNames.Add(NistObjectIdentifiers.IdAes256Cbc, "AESMac");
+            MacAlgNames.Add(PkcsObjectIdentifiers.RC2Cbc, "RC2Mac");
+        }
+
+        static IDigest GetPrf(AlgorithmIdentifier algID)
+        {
+            return ((DigestCreator)prfs[algID]).Invoke();
+        }
+
+
+        static IWrapper CreateRFC3211Wrapper(DerObjectIdentifier algorithm)
+
+        {
+            if (NistObjectIdentifiers.IdAes128Cbc.Equals(algorithm)
+        || NistObjectIdentifiers.IdAes192Cbc.Equals(algorithm)
+        || NistObjectIdentifiers.IdAes256Cbc.Equals(algorithm))
+            {
+                return new Rfc3211WrapEngine(new AesEngine());
+            }
+            else if (PkcsObjectIdentifiers.DesEde3Cbc.Equals(algorithm))
+            {
+                return new Rfc3211WrapEngine(new DesEdeEngine());
+            }
+            else if (OiwObjectIdentifiers.DesCbc.Equals(algorithm))
+            {
+                return new Rfc3211WrapEngine(new DesEngine());
+            }
+            else if (PkcsObjectIdentifiers.RC2Cbc.Equals(algorithm))
+            {
+                return new Rfc3211WrapEngine(new RC2Engine());
+            }
+            else
+            {
+                throw new CmsException("cannot recognise wrapper: " + algorithm);
+            }
+        }
+
+
+
+       public static object CreateContentCipher(bool forEncryption, ICipherParameters encKey,
+            AlgorithmIdentifier encryptionAlgID)
+
+        {
+            return CipherFactory.CreateContentCipher(forEncryption, encKey, encryptionAlgID);
+        }
+
+
+        public AlgorithmIdentifier GenerateEncryptionAlgID(DerObjectIdentifier encryptionOID, KeyParameter encKey, SecureRandom random)
+
+        {
+            return AlgorithmIdentifierFactory.GenerateEncryptionAlgID(encryptionOID, encKey.GetKey().Length * 8, random);
+        }
+
+       public  CipherKeyGenerator CreateKeyGenerator(DerObjectIdentifier algorithm, SecureRandom random)
+
+        {
+            return CipherKeyGeneratorFactory.CreateKeyGenerator(algorithm, random);
+        }
+
+
+    }
+
+    // This exists because we can't directly put a delegate in a map as it is
+    // not an object.
+    internal class DigestProvider
+    {
+        private readonly EnvelopedDataHelper.DigestCreator creator;
+
+        public DigestProvider(EnvelopedDataHelper.DigestCreator creator)
+        {
+            this.creator = creator;
+        }
+
+        public IDigest Create()
+        {
+            return creator.Invoke();
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/cms/RecipientInfoGenerator.cs b/crypto/src/cms/RecipientInfoGenerator.cs
index c41db6122..75f5dcc33 100644
--- a/crypto/src/cms/RecipientInfoGenerator.cs
+++ b/crypto/src/cms/RecipientInfoGenerator.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Cms
 {
-	interface RecipientInfoGenerator
+	public interface RecipientInfoGenerator
 	{
 		/// <summary>
 		/// Generate a RecipientInfo object for the given key.
diff --git a/crypto/src/crmf/CertificateRequestMessage.cs b/crypto/src/crmf/CertificateRequestMessage.cs
index 087e8a933..5b5d37c9e 100644
--- a/crypto/src/crmf/CertificateRequestMessage.cs
+++ b/crypto/src/crmf/CertificateRequestMessage.cs
@@ -211,8 +211,8 @@ namespace Org.BouncyCastle.Crmf
               calculator.Stream.Write(b,0,b.Length);
             }
             else
-            {
-                byte[] b = certReqMsg.GetDerEncoded();
+            {              
+                byte[] b = certReqMsg.CertReq.GetDerEncoded();
                 calculator.Stream.Write(b,0,b.Length);
             }
 
diff --git a/crypto/src/crmf/CertificateRequestMessageBuilder.cs b/crypto/src/crmf/CertificateRequestMessageBuilder.cs
index 384f6a965..9c3cf954d 100644
--- a/crypto/src/crmf/CertificateRequestMessageBuilder.cs
+++ b/crypto/src/crmf/CertificateRequestMessageBuilder.cs
@@ -95,6 +95,12 @@ namespace Org.BouncyCastle.Crmf
             return this;
         }
 
+        public CertificateRequestMessageBuilder AddControl(IControl control)
+        {
+            _controls.Add(control);
+            return this;
+        }
+
         public CertificateRequestMessageBuilder SetProofOfPossessionSignKeySigner(ISignatureFactory popoSignatureFactory)
         {
             if (_popoPrivKey != null || _popRaVerified != null || _agreeMac != null)
@@ -102,7 +108,8 @@ namespace Org.BouncyCastle.Crmf
                 throw new InvalidOperationException("only one proof of possession is allowed.");
             }
 
-            this._popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
+            this._popSigner = popoSignatureFactory;
+          
             return this;
         }
 
diff --git a/crypto/src/crmf/PKIArchiveControlBuilder.cs b/crypto/src/crmf/PKIArchiveControlBuilder.cs
new file mode 100644
index 000000000..f43ecd4ec
--- /dev/null
+++ b/crypto/src/crmf/PKIArchiveControlBuilder.cs
@@ -0,0 +1,61 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Crmf
+{
+    public class PKIArchiveControlBuilder
+    {
+        private CmsEnvelopedDataGenerator envGen;
+        private CmsProcessableByteArray keyContent;
+
+        /// <summary>
+        ///Basic constructor - specify the contents of the PKIArchiveControl structure.
+        /// </summary>
+        /// <param name="privateKeyInfo">the private key to be archived.</param>
+        /// <param name="generalName">the general name to be associated with the private key.</param>
+        ///
+        public PKIArchiveControlBuilder(PrivateKeyInfo privateKeyInfo, GeneralName generalName)
+        {
+            EncKeyWithID encKeyWithID = new EncKeyWithID(privateKeyInfo, generalName);
+
+            try
+            {
+                this.keyContent = new CmsProcessableByteArray(CrmfObjectIdentifiers.id_ct_encKeyWithID, encKeyWithID.GetEncoded());
+            }
+            catch (IOException e)
+            {
+                throw new InvalidOperationException("unable to encode key and general name info");
+            }
+
+            this.envGen = new CmsEnvelopedDataGenerator();
+        }
+        
+
+
+
+        ///<summary>Add a recipient generator to this control.</summary>       
+        ///<param name="recipientGen"> recipient generator created for a specific recipient.</param>
+        ///<returns>this builder object.</returns>       
+        public PKIArchiveControlBuilder AddRecipientGenerator(RecipientInfoGenerator recipientGen)
+        {
+            envGen.AddRecipientInfoGenerator(recipientGen);
+            return this;
+        }
+       
+        /// <summary>Build the PKIArchiveControl using the passed in encryptor to encrypt its contents.</summary>
+        /// <param name="contentEncryptor">a suitable content encryptor.</param>
+        /// <returns>a PKIArchiveControl object.</returns>
+        public PkiArchiveControl Build(ICipherBuilderWithKey contentEncryptor)
+        {                                            
+            CmsEnvelopedData envContent = envGen.Generate(keyContent, contentEncryptor);
+            EnvelopedData envD = EnvelopedData.GetInstance(envContent.ContentInfo.Content);        
+            return new PkiArchiveControl(new PkiArchiveOptions(new EncryptedKey(envD)));
+    }
+}
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/operators/Asn1Signature.cs b/crypto/src/crypto/operators/Asn1Signature.cs
index 3962a4a15..66050789e 100644
--- a/crypto/src/crypto/operators/Asn1Signature.cs
+++ b/crypto/src/crypto/operators/Asn1Signature.cs
@@ -12,6 +12,7 @@ using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto.IO;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Signers;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
@@ -346,7 +347,8 @@ namespace Org.BouncyCastle.Crypto.Operators
 		}
 
         public IStreamCalculator CreateCalculator()
-        {
+        {       
+           
             ISigner verifier = SignerUtilities.InitSigner(X509Utilities.GetSignatureName(algID), false, publicKey, null);
 
             return new DefaultVerifierCalculator(verifier);
diff --git a/crypto/src/crypto/operators/CipherFactory.cs b/crypto/src/crypto/operators/CipherFactory.cs
new file mode 100644
index 000000000..11a9faef9
--- /dev/null
+++ b/crypto/src/crypto/operators/CipherFactory.cs
@@ -0,0 +1,146 @@
+using System;
+using Org.BouncyCastle.Asn1;
+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.Asn1.X509;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Operators
+{
+    public class CipherFactory
+    {
+        private 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
+        };
+
+        public static object CreateContentCipher(bool forEncryption, ICipherParameters encKey,
+            AlgorithmIdentifier encryptionAlgID)
+        {
+            DerObjectIdentifier encAlg = encryptionAlgID.Algorithm;
+
+            if (encAlg.Equals(PkcsObjectIdentifiers.Rc4))
+            {
+                IStreamCipher cipher = new RC4Engine();
+
+                cipher.Init(forEncryption, encKey);
+
+                return cipher;
+            }
+            else
+            {
+                BufferedBlockCipher cipher = CreateCipher(encryptionAlgID.Algorithm);
+
+                Asn1Object sParams = encryptionAlgID.Parameters.ToAsn1Object();
+
+                if (sParams != null && !(sParams is DerNull))
+                {
+                    if (encAlg.Equals(PkcsObjectIdentifiers.DesEde3Cbc)
+                        || encAlg.Equals(AlgorithmIdentifierFactory.IDEA_CBC)
+                        || encAlg.Equals(NistObjectIdentifiers.IdAes128Cbc)
+                        || encAlg.Equals(NistObjectIdentifiers.IdAes192Cbc)
+                        || encAlg.Equals(NistObjectIdentifiers.IdAes256Cbc)
+                        || encAlg.Equals(NttObjectIdentifiers.IdCamellia128Cbc)
+                        || encAlg.Equals(NttObjectIdentifiers.IdCamellia192Cbc)
+                        || encAlg.Equals(NttObjectIdentifiers.IdCamellia256Cbc)
+                        || encAlg.Equals(KisaObjectIdentifiers.IdSeedCbc)
+                        || encAlg.Equals(OiwObjectIdentifiers.DesCbc))
+                    {
+                        cipher.Init(forEncryption, new ParametersWithIV(encKey,
+                            Asn1OctetString.GetInstance(sParams).GetOctets()));
+                    }
+                    else if (encAlg.Equals(AlgorithmIdentifierFactory.CAST5_CBC))
+                    {
+                        Cast5CbcParameters cbcParams = Cast5CbcParameters.GetInstance(sParams);
+
+                        cipher.Init(forEncryption, new ParametersWithIV(encKey, cbcParams.GetIV()));
+                    }
+                    else if (encAlg.Equals(PkcsObjectIdentifiers.RC2Cbc))
+                    {
+                        RC2CbcParameter cbcParams = RC2CbcParameter.GetInstance(sParams);
+
+                        cipher.Init(forEncryption, new ParametersWithIV(new RC2Parameters(((KeyParameter)encKey).GetKey(), rc2Ekb[cbcParams.RC2ParameterVersion.IntValue]), cbcParams.GetIV()));
+                    }
+                    else
+                    {
+                        throw new InvalidOperationException("cannot match parameters");
+                    }
+                }
+                else
+                {
+                    if (encAlg.Equals(PkcsObjectIdentifiers.DesEde3Cbc)
+                        || encAlg.Equals(AlgorithmIdentifierFactory.IDEA_CBC)
+                        || encAlg.Equals(AlgorithmIdentifierFactory.CAST5_CBC))
+                    {
+                        cipher.Init(forEncryption, new ParametersWithIV(encKey, new byte[8]));
+                    }
+                    else
+                    {
+                        cipher.Init(forEncryption, encKey);
+                    }
+                }
+
+                return cipher;
+            }
+
+        }
+
+        private static BufferedBlockCipher CreateCipher(DerObjectIdentifier algorithm)
+        {
+            IBlockCipher cipher;
+
+            if (NistObjectIdentifiers.IdAes128Cbc.Equals(algorithm)
+        || NistObjectIdentifiers.IdAes192Cbc.Equals(algorithm)
+        || NistObjectIdentifiers.IdAes256Cbc.Equals(algorithm))
+            {
+                cipher = new CbcBlockCipher(new AesEngine());
+            }
+            else if (PkcsObjectIdentifiers.DesEde3Cbc.Equals(algorithm))
+            {
+                cipher = new CbcBlockCipher(new DesEdeEngine());
+            }
+            else if (OiwObjectIdentifiers.DesCbc.Equals(algorithm))
+            {
+                cipher = new CbcBlockCipher(new DesEngine());
+            }
+            else if (PkcsObjectIdentifiers.RC2Cbc.Equals(algorithm))
+            {
+                cipher = new CbcBlockCipher(new RC2Engine());
+            }
+            else if (MiscObjectIdentifiers.cast5CBC.Equals(algorithm))
+            {
+                cipher = new CbcBlockCipher(new Cast5Engine());
+            }
+            else
+            {
+                throw new InvalidOperationException("cannot recognise cipher: " + algorithm);
+            }
+
+            return new PaddedBufferedBlockCipher(cipher, new Pkcs7Padding());
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/operators/CmsContentEncryptorBuilder.cs b/crypto/src/crypto/operators/CmsContentEncryptorBuilder.cs
new file mode 100644
index 000000000..f7ddf4db6
--- /dev/null
+++ b/crypto/src/crypto/operators/CmsContentEncryptorBuilder.cs
@@ -0,0 +1,155 @@
+using System.Collections;
+using System.IO;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Operators
+{
+    public class CmsContentEncryptorBuilder
+    {
+        private static readonly IDictionary keySizes = Platform.CreateHashtable();
+
+        static CmsContentEncryptorBuilder()
+        {
+            keySizes[NistObjectIdentifiers.IdAes128Cbc] = 128;
+            keySizes[NistObjectIdentifiers.IdAes192Cbc] =192;
+            keySizes[NistObjectIdentifiers.IdAes256Cbc] =256;
+
+           
+            keySizes[NttObjectIdentifiers.IdCamellia128Cbc] =128;
+            keySizes[NttObjectIdentifiers.IdCamellia192Cbc] =192;
+            keySizes[NttObjectIdentifiers.IdCamellia256Cbc] =256;
+        }
+
+        private static int getKeySize(DerObjectIdentifier oid)
+        {
+            if (keySizes.Contains(oid))
+            {
+                return (int)keySizes[oid];
+            }
+
+            return -1;
+        }
+
+        private readonly DerObjectIdentifier encryptionOID;
+        private readonly int keySize;
+
+      
+        private EnvelopedDataHelper helper = new EnvelopedDataHelper();
+        private SecureRandom random;
+
+        public CmsContentEncryptorBuilder(DerObjectIdentifier encryptionOID):this(encryptionOID, getKeySize(encryptionOID)) { 
+        }
+
+        public CmsContentEncryptorBuilder(DerObjectIdentifier encryptionOID, int keySize)
+        {
+            this.encryptionOID = encryptionOID;
+            this.keySize = keySize;
+        }
+
+        public ICipherBuilderWithKey Build()
+         {
+            return new DefaultCipherBuilderWithKey(encryptionOID,keySize,random,new EnvelopedDataHelper());
+        }
+
+    }
+
+    public class DefaultCipherBuilderWithKey:ICipherBuilderWithKey
+    {
+
+        private readonly KeyParameter encKey;
+        private AlgorithmIdentifier algorithmIdentifier;
+       
+      
+
+
+        public DefaultCipherBuilderWithKey(DerObjectIdentifier encryptionOID, int keySize, SecureRandom random,EnvelopedDataHelper helper)
+        {
+            if (random == null)
+            {
+                random= new SecureRandom();
+            }
+
+            CipherKeyGenerator keyGen = helper.CreateKeyGenerator(encryptionOID, random);
+            encKey = new KeyParameter(keyGen.GenerateKey());
+            algorithmIdentifier = helper.GenerateEncryptionAlgID(encryptionOID, encKey, random);
+          //  cipher = EnvelopedDataHelper.CreateContentCipher(true, encKey, algorithmIdentifier);
+        }
+
+
+        public object AlgorithmDetails
+        {
+            get { return algorithmIdentifier; }
+        }
+        public int GetMaxOutputSize(int inputLen)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public ICipher BuildCipher(Stream stream)
+        {
+
+            object cipher = EnvelopedDataHelper.CreateContentCipher(true, encKey, algorithmIdentifier);
+
+            //
+            // BufferedBlockCipher
+            // IStreamCipher
+            //
+
+            if (cipher is IStreamCipher)
+            {
+                   cipher = new BufferedStreamCipher((IStreamCipher)cipher);                
+            }
+
+            if (stream == null)
+            {
+                stream = new MemoryStream();
+            }
+
+            return new BufferedCipherWrapper((IBufferedCipher)cipher,stream);
+        }
+
+        public ICipherParameters Key
+        {
+            get { return encKey; }
+        }
+    }
+
+    public class BufferedCipherWrapper : ICipher
+    {
+        private readonly IBufferedCipher bufferedCipher;
+        private readonly CipherStream stream;
+
+        public BufferedCipherWrapper(IBufferedCipher bufferedCipher, Stream source)
+        {
+            this.bufferedCipher = bufferedCipher;
+            stream = new CipherStream(source, bufferedCipher, bufferedCipher);
+        }
+
+        public int GetMaxOutputSize(int inputLen)
+        {
+            return bufferedCipher.GetOutputSize(inputLen);
+        }
+
+        public int GetUpdateOutputSize(int inputLen)
+        {
+            return bufferedCipher.GetUpdateOutputSize(inputLen);
+        }
+
+        public Stream Stream
+        {
+            get { return stream; }
+        }
+    }
+  
+
+    
+
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/util/AlgorithmIdentifierFactory.cs b/crypto/src/crypto/util/AlgorithmIdentifierFactory.cs
new file mode 100644
index 000000000..73458f0ea
--- /dev/null
+++ b/crypto/src/crypto/util/AlgorithmIdentifierFactory.cs
@@ -0,0 +1,105 @@
+using System;
+using Org.BouncyCastle.Asn1;
+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.Asn1.X509;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Utilities
+{
+    public class AlgorithmIdentifierFactory
+    {
+        public static readonly DerObjectIdentifier IDEA_CBC = new DerObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2");
+        public static readonly DerObjectIdentifier CAST5_CBC = new DerObjectIdentifier("1.2.840.113533.7.66.10");
+
+        private 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
+        };
+
+
+        /**
+    * Create an AlgorithmIdentifier for the passed in encryption algorithm.
+    *
+    * @param encryptionOID OID for the encryption algorithm
+    * @param keySize key size in bits (-1 if unknown)
+    * @param random SecureRandom to use for parameter generation.
+    * @return a full AlgorithmIdentifier including parameters
+    * @throws IllegalArgumentException if encryptionOID cannot be matched
+    */
+        public static AlgorithmIdentifier GenerateEncryptionAlgID(DerObjectIdentifier encryptionOID, int keySize, SecureRandom random)
+
+        {
+            if (encryptionOID.Equals(NistObjectIdentifiers.IdAes128Cbc)
+                    || encryptionOID.Equals(NistObjectIdentifiers.IdAes192Cbc)
+                    || encryptionOID.Equals(NistObjectIdentifiers.IdAes256Cbc)
+                    || encryptionOID.Equals(NttObjectIdentifiers.IdCamellia128Cbc)
+                    || encryptionOID.Equals(NttObjectIdentifiers.IdCamellia192Cbc)
+                    || encryptionOID.Equals(NttObjectIdentifiers.IdCamellia256Cbc)
+                    || encryptionOID.Equals(KisaObjectIdentifiers.IdSeedCbc))
+            {
+                byte[] iv = new byte[16];
+
+                random.NextBytes(iv);
+
+                return new AlgorithmIdentifier(encryptionOID, new DerOctetString(iv));
+            }
+            else if (encryptionOID.Equals(PkcsObjectIdentifiers.DesEde3Cbc)
+                    || encryptionOID.Equals(IDEA_CBC)
+                    || encryptionOID.Equals(OiwObjectIdentifiers.DesCbc))
+            {
+                byte[] iv = new byte[8];
+
+                random.NextBytes(iv);
+
+                return new AlgorithmIdentifier(encryptionOID, new DerOctetString(iv));
+            }
+            else if (encryptionOID.Equals(CAST5_CBC))
+            {
+                byte[] iv = new byte[8];
+
+                random.NextBytes(iv);
+
+                Cast5CbcParameters cbcParams = new Cast5CbcParameters(iv, keySize);
+
+                return new AlgorithmIdentifier(encryptionOID, cbcParams);
+            }
+            else if (encryptionOID.Equals(PkcsObjectIdentifiers.Rc4))
+            {
+                return new AlgorithmIdentifier(encryptionOID, DerNull.Instance);
+            }
+            else if (encryptionOID.Equals(PkcsObjectIdentifiers.RC2Cbc))
+            {
+                byte[] iv = new byte[8];
+
+                random.NextBytes(iv);
+
+                RC2CbcParameter cbcParams = new RC2CbcParameter(rc2Table[128], iv);
+
+                return new AlgorithmIdentifier(encryptionOID, cbcParams);
+            }
+            else
+            {
+                throw new InvalidOperationException("unable to match algorithm");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/util/CipherKeyGeneratorFactory.cs b/crypto/src/crypto/util/CipherKeyGeneratorFactory.cs
new file mode 100644
index 000000000..7a24a01a8
--- /dev/null
+++ b/crypto/src/crypto/util/CipherKeyGeneratorFactory.cs
@@ -0,0 +1,101 @@
+using System;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Kisa;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Ntt;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Utilities
+{
+    public class CipherKeyGeneratorFactory
+    {
+
+        /**
+   * Create a key generator for the passed in Object Identifier.
+   *
+   * @param algorithm the Object Identifier indicating the algorithn the generator is for.
+   * @param random a source of random to initialise the generator with.
+   * @return an initialised CipherKeyGenerator.
+   * @throws IllegalArgumentException if the algorithm cannot be identified.
+   */
+        public static CipherKeyGenerator CreateKeyGenerator(DerObjectIdentifier algorithm, SecureRandom random)
+
+        {
+            if (NistObjectIdentifiers.IdAes128Cbc.Equals(algorithm))
+            {
+                return createCipherKeyGenerator(random, 128);
+            }
+            else if (NistObjectIdentifiers.IdAes192Cbc.Equals(algorithm))
+            {
+                return createCipherKeyGenerator(random, 192);
+            }
+            else if (NistObjectIdentifiers.IdAes256Cbc.Equals(algorithm))
+            {
+                return createCipherKeyGenerator(random, 256);
+            }
+            else if (PkcsObjectIdentifiers.DesEde3Cbc.Equals(algorithm))
+            {
+                DesEdeKeyGenerator keyGen = new DesEdeKeyGenerator();
+
+                keyGen.Init(new KeyGenerationParameters(random, 192));
+
+                return keyGen;
+            }
+            else if (NttObjectIdentifiers.IdCamellia128Cbc.Equals(algorithm))
+            {
+                return createCipherKeyGenerator(random, 128);
+            }
+            else if (NttObjectIdentifiers.IdCamellia192Cbc.Equals(algorithm))
+            {
+                return createCipherKeyGenerator(random, 192);
+            }
+            else if (NttObjectIdentifiers.IdCamellia256Cbc.Equals(algorithm))
+            {
+                return createCipherKeyGenerator(random, 256);
+            }
+            else if (KisaObjectIdentifiers.IdSeedCbc.Equals(algorithm))
+            {
+                return createCipherKeyGenerator(random, 128);
+            }
+            else if (AlgorithmIdentifierFactory.CAST5_CBC.Equals(algorithm))
+            {
+                return createCipherKeyGenerator(random, 128);
+            }
+            else if (OiwObjectIdentifiers.DesCbc.Equals(algorithm))
+            {
+                DesKeyGenerator keyGen = new DesKeyGenerator();
+
+                keyGen.Init(new KeyGenerationParameters(random, 64));
+
+                return keyGen;
+            }
+            else if (PkcsObjectIdentifiers.Rc4.Equals(algorithm))
+            {
+                return createCipherKeyGenerator(random, 128);
+            }
+            else if (PkcsObjectIdentifiers.RC2Cbc.Equals(algorithm))
+            {
+                return createCipherKeyGenerator(random, 128);
+            }
+            else
+            {
+                throw new InvalidOperationException("cannot recognise cipher: " + algorithm);
+            }
+        }
+
+
+
+
+        private static CipherKeyGenerator createCipherKeyGenerator(SecureRandom random, int keySize)
+        {
+            CipherKeyGenerator keyGen = new CipherKeyGenerator();
+
+            keyGen.Init(new KeyGenerationParameters(random, keySize));
+
+            return keyGen;
+        }
+    }
+}
\ No newline at end of file
diff --git a/crypto/test/src/crmf/test/CrmfTest.cs b/crypto/test/src/crmf/test/CrmfTest.cs
new file mode 100644
index 000000000..caff0e664
--- /dev/null
+++ b/crypto/test/src/crmf/test/CrmfTest.cs
@@ -0,0 +1,191 @@
+using System;
+using System.Collections;
+using NUnit.Core;
+using NUnit.Framework;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Cmp.Tests;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Operators;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+using Org.BouncyCastle.Utilities.Test;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Crmf.Tests
+{
+    [TestFixture]
+    public class CrmfTest : SimpleTest
+    {
+
+
+        public override string Name => "CRMF Tests";
+
+
+        public override void PerformTest()
+        {
+            TestFromJVM();
+            TestBasicMessage();
+            TestBasicMessageWithArchiveControl();
+            TestBasicMessageWithArchiveControlJVMGenerated();
+        }
+
+        [Test]
+        public void TestFromJVM()
+        {
+            var pubKey = PublicKeyFactory.CreateKey(Hex.Decode(
+                "305c300d06092a864886f70d0101010500034b003048024100bbb3f6a5031fbb1feedbfed7584a4f6321ccdc16b9526b0f6e31859328db35a6ec420a98e14fb3bcf192004b1aa6fc9269410204785cc01317232feb545a7b410203010001"));
+            var privKey = PrivateKeyFactory.CreateKey(Hex.Decode("30820153020100300d06092a864886f70d01010105000482013d30820139020100024100bbb3f6a5031fbb1feedbfed7584a4f6321ccdc16b9526b0f6e31859328db35a6ec420a98e14fb3bcf192004b1aa6fc9269410204785cc01317232feb545a7b41020301000102400093b384b9021c4cd59888e956cb1e653e736833235315b0e938116da19a9276b1ea1fe33da580a497313f08eb3e7c14627508a4284be04ea3e6ba8cb4b0a5c9022100e2fe0d9f35bfd7ecf196227e5e915a2464478ea7033c6dff4ce6a02961759a49022100d3b093770745dfea42c5c5c31f1a6b797a60dfb5503ae60f70b864452c4a193902203cc761c65b91feb3070cf8377602dd6c191dbfe8a04931fac6108a9a09ea7f61022071bb2a5f06af49cfc8340d3df995ee2c03cdcc22d389f15456511abdf73f9031022065bc10d43192cb3131c53be18a0d41a060d4e0a3324a47e3eb4bf720e1b46b10"));
+
+            var rawMsg = Hex.Decode("3081cc30760201013071a511300f310d300b0603550403130454657374a65c300d06092a864886f70d0101010500034b003048024100bbb3f6a5031fbb1feedbfed7584a4f6321ccdc16b9526b0f6e31859328db35a6ec420a98e14fb3bcf192004b1aa6fc9269410204785cc01317232feb545a7b410203010001a152300d06092a864886f70d01010505000341003120cdb58edfef4a2e1a4bfe96b972007c1d1c949221d266efe28b45ba036b9d534f5dca261dce8f21e134d97e55c3bd76d1460781fd9703f8f9907d1f036c20");
+
+            var msg = new CertificateRequestMessage(rawMsg);
+            IsTrue("Pop Valid",msg.IsValidSigningKeyPop(new Asn1VerifierFactoryProvider(pubKey)));
+
+            //
+            // Vandalize message to check for failure.
+            //
+
+            rawMsg[7] ^= 1;
+            msg = new CertificateRequestMessage(rawMsg);
+                  
+            IsTrue("Pop Verified Vandalized Message!", !msg.IsValidSigningKeyPop(new Asn1VerifierFactoryProvider(pubKey)));
+
+        }
+
+
+
+        [Test]
+        public void TestBasicMessage()
+        {
+            var rsaKeyPairGenerator = new RsaKeyPairGenerator();
+            rsaKeyPairGenerator.Init(new RsaKeyGenerationParameters(BigInteger.ValueOf(65537), new SecureRandom(), 2048, 100));
+            var rsaKeyPair = rsaKeyPairGenerator.GenerateKeyPair();
+
+            var certReqBuild = new CertificateRequestMessageBuilder(BigInteger.One);
+                      
+            certReqBuild.SetSubject(new X509Name("CN=Test"))
+                .SetPublicKey(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(rsaKeyPair.Public))                
+                .SetProofOfPossessionSignKeySigner(new Asn1SignatureFactory("SHA1WithRSA", rsaKeyPair.Private));
+
+            var certificateRequestMessage = certReqBuild.Build();
+                            
+            IsTrue("Signing Key Pop Valid",certificateRequestMessage.IsValidSigningKeyPop(new Asn1VerifierFactoryProvider(rsaKeyPair.Public)));
+            IsTrue(certificateRequestMessage.GetCertTemplate().Subject.Equivalent(new X509Name("CN=Test")));
+            IsTrue(certificateRequestMessage.GetCertTemplate().PublicKey.Equals(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(rsaKeyPair.Public)));
+        }
+
+        [Test]
+        public void TestBasicMessageWithArchiveControl()
+        {
+            var rsaKeyPairGenerator = new RsaKeyPairGenerator();
+            rsaKeyPairGenerator.Init(new RsaKeyGenerationParameters(BigInteger.ValueOf(65537), new SecureRandom(), 2048, 100));
+            var rsaKeyPair = rsaKeyPairGenerator.GenerateKeyPair();
+
+            var tcb = new TestCertBuilder()
+            {
+                PublicKey = rsaKeyPair.Public,
+                Subject = new X509Name("CN=Test"),
+                Issuer = new X509Name("CN=Test"),
+                NotBefore = DateTime.UtcNow.AddDays(-1),
+                NotAfter = DateTime.UtcNow.AddDays(1),
+                SignatureAlgorithm = "Sha1WithRSAEncryption"
+            };
+
+            var cert = tcb.Build(rsaKeyPair.Private);
+
+            var publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(rsaKeyPair.Public);
+            var privateInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(rsaKeyPair.Private);
+
+
+            var certificateRequestMessageBuilder = new CertificateRequestMessageBuilder(BigInteger.One);
+            certificateRequestMessageBuilder.SetSubject(new X509Name("CN=Test"));
+            certificateRequestMessageBuilder.SetPublicKey(publicKeyInfo);
+           
+            certificateRequestMessageBuilder.AddControl(
+                new PKIArchiveControlBuilder(privateInfo, new GeneralName(new X509Name("CN=Test")))
+                    .AddRecipientGenerator(new KeyTransRecipientInfoGenerator()
+                    {
+                        RecipientCert = cert,
+                        SubjectKeyIdentifier = (DerOctetString)SubjectKeyIdentifier.CreateSha1KeyIdentifier(publicKeyInfo).ToAsn1Object()
+                     }).Build(new CmsContentEncryptorBuilder(NistObjectIdentifiers.IdAes128Cbc)
+                        .Build())
+            );
+
+            var msg = certificateRequestMessageBuilder.Build();
+
+            IsTrue(Arrays.AreEqual(msg.GetCertTemplate().Subject.GetEncoded(), new X509Name("CN=Test").GetEncoded()));
+            IsTrue(Arrays.AreEqual(msg.GetCertTemplate().PublicKey.GetEncoded(),publicKeyInfo.GetEncoded()));
+
+            checkCertReqMsgWithArchiveControl(rsaKeyPair,msg);
+            checkCertReqMsgWithArchiveControl(rsaKeyPair, new CertificateRequestMessage(msg.GetEncoded()));
+    
+        }
+
+        [Test]
+        public void TestBasicMessageWithArchiveControlJVMGenerated()
+        {
+            AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey(
+                Hex.Decode("305c300d06092a864886f70d0101010500034b003048024100a9a94b7b98dc3daf8cac032a14bd4510832b0e007edbdafc065e328645a35828b8185cdbf73ed495c88436b11a9322965595d2e4c1dd63c3c4d41812f876b3070203010001"));
+            AsymmetricKeyParameter privateKey = PrivateKeyFactory.CreateKey(
+                Hex.Decode("30820154020100300d06092a864886f70d01010105000482013e3082013a020100024100a9a94b7b98dc3daf8cac032a14bd4510832b0e007edbdafc065e328645a35828b8185cdbf73ed495c88436b11a9322965595d2e4c1dd63c3c4d41812f876b307020301000102400831deacfe21a9331902d7f648e1297c563196b00c70971fb439098cb5c1618925bdbac4c66b30f8956660220f326f51e5a1725ce690165154fb62fa14497265022100e54943be1b4951e127f6e79c5ab333cba4b0fff0b5e59328d6393ba98dc0e6c3022100bd6da58ce195146a1d3825ec2a622cf4962da653096bea87fbd9a94db266a66d0221008948bcceeef78f97089ec53ed0efcb6b7b489f7638f32491a6f2cdce4f99d89102204eb1b066d8883054ed12985e863506ec0d3fa5ab356cc99ff876b228ff0639f9022024049aaf39bf9a0ddfbd4caee277d0a9f07d075faae12571176a5c0ca40415c0"));
+        
+            CertificateRequestMessage msg = new CertificateRequestMessage(
+                Hex.Decode("308202af308202ab0201013071a511300f310d300b0603550403130454657374a65c300d06092a864886f70d0101010500034b003048024100a9a94b7b98dc3daf8cac032a14bd4510832b0e007edbdafc065e328645a35828b8185cdbf73ed495c88436b11a9322965595d2e4c1dd63c3c4d41812f876b3070203010001308202313082022d06092b0601050507050104a082021ea082021a0201003171306f0201003019300f310d300b06035504030c04546573740206016859de5806300d06092a864886f70d0101010500044066f1a72f808908af784b83c07895276104d7c4caaee6090212ce5b27517aec510425b784352b5342c999f844b8796286f10a59807e290f06aa39f8cba86dd6bf308201a0060b2a864886f70d0109100115301d060960864801650304010204104aceaa277cc7974ea2a775ff9db6062580820170c648e70c25c4789d2ff4ed398e5536efb45d2dd8ba76a628ad30bf9596a18337afc0f596f0c18e05fb3fa9944ed9691dae1d9b327b5bbafaaa63efb0e22d675811c27bfb023b80184325fd4b67b3b9e41bf43c5583a86433b230e09a34b61397ddff0eadf10c883fc1f01860e2a56ab4002dcc4d4925c53e09dde0b99928fdf602bce544722155cebd8816e91a411a99feea07695774cd8883034022d57f64e9cd3383c3125c48db2936b7395a22b17910be1f2c0b8650bdb5bd752ffc40fcd30169e5ae3a4ac7ad9cc850e9c17bbcf8e1a1898d0d8be19145c484467b8f1124657a5e08c10fc67416274990cc16d55c9fb76c265dd436b7e803425892297f1a08e4fab8e178874b2b3bf9c749693d609db208e9a3ebbddd26cd6a1b33c0201532170dc6c303e7ac0c42ba0bc54dfb928b228842b6bb08d8dc411d262dabf140a8b5a5c67ea486c1877a2fc000981d54cf2decaf1cfeebcf83134992b09a2b1fe9e02da25b874604b5d8bbd609875ba8"));
+
+            AsymmetricCipherKeyPair rsaKeyPair = new AsymmetricCipherKeyPair(publicKey,privateKey);
+
+
+            SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+
+
+            Console.WriteLine(msg.GetCertTemplate().Subject.Equivalent(new X509Name("CN=Test")));
+
+            IsTrue(msg.GetCertTemplate().Subject.Equivalent(new X509Name("CN=Test")));
+            IsTrue(Arrays.AreEqual(msg.GetCertTemplate().PublicKey.GetEncoded(), publicKeyInfo.GetEncoded()));
+
+            checkCertReqMsgWithArchiveControl(rsaKeyPair, msg);
+            checkCertReqMsgWithArchiveControl(rsaKeyPair, new CertificateRequestMessage(msg.GetEncoded()));
+        
+            checkCertReqMsgWithArchiveControl(rsaKeyPair,msg);
+        }
+
+        private void checkCertReqMsgWithArchiveControl(AsymmetricCipherKeyPair kp, CertificateRequestMessage certReqMessage)
+        {
+            var archiveControl =
+                (PkiArchiveControl) certReqMessage.GetControl(CrmfObjectIdentifiers.id_regCtrl_pkiArchiveOptions);
+            IsEquals("Archive type", PkiArchiveControl.encryptedPrivKey, archiveControl.ArchiveType);
+
+            IsTrue(archiveControl.EnvelopedData);
+            RecipientInformationStore recips = archiveControl.GetEnvelopedData().GetRecipientInfos();
+
+            ArrayList collection =  (ArrayList)recips.GetRecipients();
+
+            IsTrue(collection.Count == 1);
+            KeyTransRecipientInformation info = (KeyTransRecipientInformation)collection[0];
+
+            EncKeyWithID encKeyWithId = EncKeyWithID.GetInstance(info.GetContent(kp.Private));
+           
+            IsTrue(encKeyWithId.HasIdentifier);
+            IsTrue(!encKeyWithId.IsIdentifierUtf8String); // GeneralName at this point.
+
+            
+            IsTrue("Name", X509Name.GetInstance(GeneralName.GetInstance(encKeyWithId.Identifier).Name).Equivalent(new X509Name("CN=Test")));
+
+            PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(kp.Private);
+            IsTrue("Private Key", Arrays.AreEqual(privateKeyInfo.GetEncoded(), encKeyWithId.PrivateKey.GetEncoded()));
+                            
+        }
+
+    }
+}
\ No newline at end of file