summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorDavid Hook <dgh@bouncycastle.org>2019-01-15 11:01:18 +1100
committerDavid Hook <dgh@bouncycastle.org>2019-01-15 11:01:18 +1100
commitf25f7bed6807096d9a67d31f547398c1f6f213e4 (patch)
treee05afc98f495985870a7b4edbf8ab45f63a75e68 /crypto/src
parentadded alg constructor (diff)
downloadBouncyCastle.NET-ed25519-f25f7bed6807096d9a67d31f547398c1f6f213e4.tar.xz
first cut on Pkcs8
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/crmf/EncryptedValueBuilder.cs163
-rw-r--r--crypto/src/crmf/IEncryptedValuePadder.cs29
-rw-r--r--crypto/src/crypto/ICipher.cs43
-rw-r--r--crypto/src/crypto/ICipherBuilder.cs31
-rw-r--r--crypto/src/crypto/ICipherBuilderWithKey.cs14
-rw-r--r--crypto/src/crypto/IDecryptorBuilderProvider.cs18
-rw-r--r--crypto/src/crypto/Security.cs108
-rw-r--r--crypto/src/pkcs/Pkcs8EncryptedPrivateKeyInfo.cs106
-rw-r--r--crypto/src/pkcs/Pkcs8EncryptedPrivateKeyInfoBuilder.cs52
-rw-r--r--crypto/src/pkcs/PkcsException.cs18
-rw-r--r--crypto/src/pkcs/PkcsIOException.cs19
-rw-r--r--crypto/src/util/io/MemoryInputStream.cs13
-rw-r--r--crypto/src/util/io/MemoryOutputStream.cs10
13 files changed, 624 insertions, 0 deletions
diff --git a/crypto/src/crmf/EncryptedValueBuilder.cs b/crypto/src/crmf/EncryptedValueBuilder.cs
new file mode 100644
index 000000000..f9279bd53
--- /dev/null
+++ b/crypto/src/crmf/EncryptedValueBuilder.cs
@@ -0,0 +1,163 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Crmf;
+using System.IO;
+using Org.BouncyCastle.Pkcs;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.X509;
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Crmf
+{
+    public class EncryptedValueBuilder
+    {
+        private IKeyWrapper wrapper;
+        private ICipherBuilderWithKey encryptor;
+        private EncryptedValuePadder padder;
+
+        /**
+         * Create a builder that makes EncryptedValue structures.
+         *
+         * @param wrapper a wrapper for key used to encrypt the actual data contained in the EncryptedValue.
+         * @param encryptor  an output encryptor to encrypt the actual data contained in the EncryptedValue. 
+         */
+        public EncryptedValueBuilder(IKeyWrapper wrapper, ICipherBuilderWithKey encryptor) : this(wrapper, encryptor, null)
+        {
+        }
+
+        /**
+         * Create a builder that makes EncryptedValue structures with fixed length blocks padded using the passed in padder.
+         *
+         * @param wrapper a wrapper for key used to encrypt the actual data contained in the EncryptedValue.
+         * @param encryptor  an output encryptor to encrypt the actual data contained in the EncryptedValue.
+         * @param padder a padder to ensure that the EncryptedValue created will always be a constant length.
+         */
+        public EncryptedValueBuilder(IKeyWrapper wrapper, ICipherBuilderWithKey encryptor, EncryptedValuePadder padder)
+        {
+            this.wrapper = wrapper;
+            this.encryptor = encryptor;
+            this.padder = padder;
+        }
+
+        /**
+         * Build an EncryptedValue structure containing the passed in pass phrase.
+         *
+         * @param revocationPassphrase  a revocation pass phrase.
+         * @return an EncryptedValue containing the encrypted pass phrase.
+         * @throws CrmfException on a failure to encrypt the data, or wrap the symmetric key for this value.
+         */
+        public EncryptedValue Build(char[] revocationPassphrase)
+        {
+            return encryptData(padData(Strings.ToUtf8ByteArray(revocationPassphrase)));
+        }
+
+        /**
+         * Build an EncryptedValue structure containing the certificate contained in
+         * the passed in holder.
+         *
+         * @param holder  a holder containing a certificate.
+         * @return an EncryptedValue containing the encrypted certificate.
+         * @throws CrmfException on a failure to encrypt the data, or wrap the symmetric key for this value.
+         */
+        public EncryptedValue Build(X509Certificate holder)
+        {
+            try
+            {
+                return encryptData(padData(holder.GetEncoded()));
+            }
+            catch (IOException e)
+            {
+                throw new CrmfException("cannot encode certificate: " + e.Message, e);
+            }
+        }
+
+        /**
+         * Build an EncryptedValue structure containing the private key contained in
+         * the passed info structure.
+         *
+         * @param privateKeyInfo  a PKCS#8 private key info structure.
+         * @return an EncryptedValue containing an EncryptedPrivateKeyInfo structure.
+         * @throws CrmfException on a failure to encrypt the data, or wrap the symmetric key for this value.
+         */
+        public EncryptedValue Build(PrivateKeyInfo privateKeyInfo)
+        {
+            Pkcs8EncryptedPrivateKeyInfoBuilder encInfoBldr = new Pkcs8EncryptedPrivateKeyInfoBuilder(privateKeyInfo);
+
+            AlgorithmIdentifier intendedAlg = privateKeyInfo.PrivateKeyAlgorithm;
+            AlgorithmIdentifier symmAlg = (AlgorithmIdentifier)encryptor.AlgorithmDetails;
+            DerBitString encSymmKey;
+
+            try
+            {
+                Pkcs8EncryptedPrivateKeyInfo encInfo = encInfoBldr.Build(encryptor);
+
+                encSymmKey = new DerBitString(wrapper.Wrap(((KeyParameter)encryptor.Key).GetKey()).Collect());
+
+                AlgorithmIdentifier keyAlg = (AlgorithmIdentifier)wrapper.AlgorithmDetails;
+                Asn1OctetString valueHint = null;
+
+                return new EncryptedValue(intendedAlg, symmAlg, encSymmKey, keyAlg, valueHint, new DerBitString(encInfo.GetEncryptedData()));
+            }
+            catch (Exception e)
+            {
+                throw new CrmfException("cannot wrap key: " + e.Message, e);
+            }
+        }
+
+        private EncryptedValue encryptData(byte[] data)
+        {
+            MemoryOutputStream bOut = new MemoryOutputStream();
+
+            Stream eOut = encryptor.BuildCipher(bOut).Stream;
+
+            try
+            {
+                eOut.Write(data, 0, data.Length);
+
+                eOut.Close();
+            }
+            catch (IOException e)
+            {
+                throw new CrmfException("cannot process data: " + e.Message, e);
+            }
+
+            AlgorithmIdentifier intendedAlg = null;
+            AlgorithmIdentifier symmAlg = (AlgorithmIdentifier)encryptor.AlgorithmDetails;
+            DerBitString encSymmKey;
+
+            try
+            {
+                encSymmKey = new DerBitString(wrapper.Wrap(((KeyParameter)encryptor.Key).GetKey()).Collect());
+            }
+            catch (Exception e)
+            {
+                throw new CrmfException("cannot wrap key: " + e.Message, e);
+            }
+
+            AlgorithmIdentifier keyAlg = (AlgorithmIdentifier)wrapper.AlgorithmDetails;
+            Asn1OctetString valueHint = null;
+            DerBitString encValue = new DerBitString(bOut.ToArray());
+
+            return new EncryptedValue(intendedAlg, symmAlg, encSymmKey, keyAlg, valueHint, encValue);
+        }
+
+        private byte[] padData(byte[] data)
+        {
+            if (padder != null)
+            {
+                return padder.GetPaddedData(data);
+            }
+
+            return data;
+        }
+    }
+}
diff --git a/crypto/src/crmf/IEncryptedValuePadder.cs b/crypto/src/crmf/IEncryptedValuePadder.cs
new file mode 100644
index 000000000..b620186dc
--- /dev/null
+++ b/crypto/src/crmf/IEncryptedValuePadder.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Org.BouncyCastle.Crmf
+{
+    /**
+     * An encrypted value padder is used to make sure that prior to a value been
+     * encrypted the data is padded to a standard length.
+     */
+    public interface EncryptedValuePadder
+    {
+        /**
+         * Return a byte array of padded data.
+         *
+         * @param data the data to be padded.
+         * @return a padded byte array containing data.
+         */
+        byte[] GetPaddedData(byte[] data);
+
+        /**
+         * Return a byte array of with padding removed.
+         *
+         * @param paddedData the data to be padded.
+         * @return an array containing the original unpadded data.
+         */
+        byte[] GetUnpaddedData(byte[] paddedData);
+    }
+}
diff --git a/crypto/src/crypto/ICipher.cs b/crypto/src/crypto/ICipher.cs
new file mode 100644
index 000000000..9041e61ad
--- /dev/null
+++ b/crypto/src/crypto/ICipher.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /// <summary>
+    /// Base interface for a ciphers that do not require data to be block aligned.
+    /// <para>
+    /// Note: In cases where the underlying algorithm is block based, these ciphers may add or remove padding as needed.
+    /// </para>
+    /// </summary>
+    public interface ICipher
+    {
+        /// <summary>
+        /// Return the size of the output buffer required for a Write() plus a
+        /// close() with the write() being passed inputLen bytes.
+        /// <para>
+        /// The returned size may be dependent on the initialisation of this cipher
+        /// and may not be accurate once subsequent input data is processed as the cipher may
+        /// add, add or remove padding, as it sees fit.
+        /// </para>
+        /// </summary>
+        /// <returns>The space required to accommodate a call to processBytes and doFinal with inputLen bytes of input.</returns>
+        /// <param name="inputLen">The length of the expected input.</param>
+        int GetMaxOutputSize(int inputLen);
+
+        /// <summary>
+        /// Return the size of the output buffer required for a write() with the write() being
+        /// passed inputLen bytes and just updating the cipher output.
+        /// </summary>
+        /// <returns>The space required to accommodate a call to processBytes with inputLen bytes of input.</returns>
+        /// <param name="inputLen">The length of the expected input.</param>
+        int GetUpdateOutputSize(int inputLen);
+
+        /// <summary>
+        /// Gets the stream for reading/writing data processed/to be processed.
+        /// </summary>
+        /// <value>The stream associated with this cipher.</value>
+        Stream Stream { get; }
+    }
+}
diff --git a/crypto/src/crypto/ICipherBuilder.cs b/crypto/src/crypto/ICipherBuilder.cs
new file mode 100644
index 000000000..5d4d1279c
--- /dev/null
+++ b/crypto/src/crypto/ICipherBuilder.cs
@@ -0,0 +1,31 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /// <summary>
+    /// Base interface for cipher builders.
+    /// </summary>
+	public interface ICipherBuilder
+	{
+        /// <summary>
+        /// Return the algorithm and parameter details associated with any cipher built.
+        /// </summary>
+        Object AlgorithmDetails { get ; }
+
+        /// <summary>
+        /// Return the maximum output size that a given input will produce.
+        /// </summary>
+        /// <param name="inputLen">the length of the expected input.</param>
+        /// <returns>The maximum possible output size that can produced for the expected input length.</returns>
+        int GetMaxOutputSize (int inputLen);
+
+        /// <summary>
+        /// Build a cipher that operates on the passed in stream.
+        /// </summary>
+        /// <param name="stream">The stream to write/read any encrypted/decrypted data.</param>
+        /// <returns>A cipher based around the given stream.</returns>
+        ICipher BuildCipher(Stream stream);
+	}
+}
+
diff --git a/crypto/src/crypto/ICipherBuilderWithKey.cs b/crypto/src/crypto/ICipherBuilderWithKey.cs
new file mode 100644
index 000000000..01a7a2caf
--- /dev/null
+++ b/crypto/src/crypto/ICipherBuilderWithKey.cs
@@ -0,0 +1,14 @@
+
+namespace Org.BouncyCastle.Crypto
+{
+    /// <summary>
+    /// A cipher builder that can also return the key it was initialized with.
+    /// </summary>
+    public interface ICipherBuilderWithKey: ICipherBuilder
+    {
+        /// <summary>
+        /// Return the key we were initialized with.
+        /// </summary>
+        ICipherParameters Key { get; }
+    }
+}
diff --git a/crypto/src/crypto/IDecryptorBuilderProvider.cs b/crypto/src/crypto/IDecryptorBuilderProvider.cs
new file mode 100644
index 000000000..7f151e3ae
--- /dev/null
+++ b/crypto/src/crypto/IDecryptorBuilderProvider.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /// <summary>
+    /// Interface describing a provider of cipher builders for creating decrypting ciphers.
+    /// </summary>
+    public interface IDecryptorBuilderProvider
+	{
+        /// <summary>
+        /// Return a cipher builder for creating decrypting ciphers.
+        /// </summary>
+        /// <param name="algorithmDetails">The algorithm details/parameters to use to create the final cipher.</param>
+        /// <returns>A new cipher builder.</returns>
+        ICipherBuilder CreateDecryptorBuilder (Object algorithmDetails);
+    }
+}
+
diff --git a/crypto/src/crypto/Security.cs b/crypto/src/crypto/Security.cs
new file mode 100644
index 000000000..716679044
--- /dev/null
+++ b/crypto/src/crypto/Security.cs
@@ -0,0 +1,108 @@
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Engines;
+using Org.BouncyCastle.Crypto.Generators;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Paddings;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using System;
+using System.Text;
+
+namespace crypto
+{
+    public class Security
+    {
+        // USAGE
+
+        //var key = Security.GenerateText(32);
+
+        //var iv = Security.GenerateText(16);
+
+        //var encrypted = Security.Encrypt("MY SECRET", key, iv);
+
+        //var dencrypted = Security.Decrypt(encrypted, key, iv);
+
+
+        /// <summary>
+        /// Return a salted hash based on PBKDF2 for the UTF-8 encoding of the argument text.
+        /// </summary>
+        /// <param name="text">Provided key text</param>
+        /// <param name="salt">Base64 encoded string representing the salt</param>
+        /// <returns></returns>
+        public static String ComputeHash(string text, string salt)
+        {
+            var data = Encoding.UTF8.GetBytes(text);
+            var sha = new Sha512Digest();
+            var gen = new Pkcs5S2ParametersGenerator(sha);
+
+            gen.Init(data, Convert.FromBase64String(salt), 2048);
+
+            return Convert.ToBase64String(((KeyParameter)gen.GenerateDerivedParameters(sha.GetDigestSize() * 8)).GetKey());
+        }
+
+        public static String Decrypt(String cipherText, String key, String iv)
+
+        {
+
+            var cipher = CreateCipher(false, key, iv);
+
+            var textAsBytes = cipher.DoFinal(Convert.FromBase64String(cipherText));
+
+
+
+            return Encoding.UTF8.GetString(textAsBytes, 0, textAsBytes.Length);
+
+        }
+
+
+
+        public static String Encrypt(String plainText, String key, String iv)
+
+        {
+
+            var cipher = CreateCipher(true, key, iv);
+
+
+
+            return Convert.ToBase64String(cipher.DoFinal(Encoding.UTF8.GetBytes(plainText)));
+
+        }
+
+
+
+        public static String GenerateText(int size)
+
+        {
+
+            var textAsBytes = new Byte[size];
+
+            var secureRandom = SecureRandom.GetInstance("SHA256PRNG", true);
+
+
+
+            secureRandom.NextBytes(textAsBytes);
+
+            return Convert.ToBase64String(textAsBytes);
+
+        }
+
+
+
+        private static PaddedBufferedBlockCipher CreateCipher(Boolean isEncryption, String key, String iv)
+
+        {
+
+            var cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(new RijndaelEngine()), new ISO10126d2Padding());
+
+            var keyParam = new KeyParameter(Convert.FromBase64String(key));
+
+            ICipherParameters cipherParams = String.IsNullOrEmpty(iv) ? (ICipherParameters)keyParam : new ParametersWithIV(keyParam, Convert.FromBase64String(iv));
+
+            cipher.Init(isEncryption, cipherParams);
+
+            return cipher;
+
+        }
+    }
+}
diff --git a/crypto/src/pkcs/Pkcs8EncryptedPrivateKeyInfo.cs b/crypto/src/pkcs/Pkcs8EncryptedPrivateKeyInfo.cs
new file mode 100644
index 000000000..4c4ae83eb
--- /dev/null
+++ b/crypto/src/pkcs/Pkcs8EncryptedPrivateKeyInfo.cs
@@ -0,0 +1,106 @@
+
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities.IO;
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Pkcs
+{
+    /// <summary>
+    /// A holding class for a PKCS#8 encrypted private key info object that allows for its decryption.
+    /// </summary>
+    public class Pkcs8EncryptedPrivateKeyInfo
+    {
+        private EncryptedPrivateKeyInfo encryptedPrivateKeyInfo;
+
+        private static EncryptedPrivateKeyInfo parseBytes(byte[] pkcs8Encoding)
+        {
+            try
+            {
+                return EncryptedPrivateKeyInfo.GetInstance(pkcs8Encoding);
+            }
+
+            catch (ArgumentException e)
+            {
+                throw new PkcsIOException("malformed data: " + e.Message, e);
+            }
+            catch (Exception e)
+            {
+                throw new PkcsIOException("malformed data: " + e.Message, e);
+            }
+        }
+
+        /// <summary>
+        /// Base constructor from a PKCS#8 EncryptedPrivateKeyInfo object.
+        /// </summary>
+        /// <param name="encryptedPrivateKeyInfo">A PKCS#8 EncryptedPrivateKeyInfo object.</param>
+        public Pkcs8EncryptedPrivateKeyInfo(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo)
+        {
+            this.encryptedPrivateKeyInfo = encryptedPrivateKeyInfo;
+        }
+
+        /// <summary>
+        /// Base constructor from a BER encoding of a PKCS#8 EncryptedPrivateKeyInfo object.
+        /// </summary>
+        /// <param name="encryptedPrivateKeyInfo">A BER encoding of a PKCS#8 EncryptedPrivateKeyInfo objects.</param>
+        public Pkcs8EncryptedPrivateKeyInfo(byte[] encryptedPrivateKeyInfo) : this(parseBytes(encryptedPrivateKeyInfo))
+        {
+
+        }
+
+        /// <summary>
+        /// Returns the underlying ASN.1 structure inside this object.
+        /// </summary>
+        /// <returns>Return the EncryptedPrivateKeyInfo structure in this object.</returns>
+        public EncryptedPrivateKeyInfo ToAsn1Structure()
+        {
+            return encryptedPrivateKeyInfo;
+        }
+
+        /// <summary>
+        /// Returns a copy of the encrypted data in this structure.
+        /// </summary>
+        /// <returns>Return a copy of the encrypted data in this object.</returns>
+        public byte[] GetEncryptedData()
+        {
+            return encryptedPrivateKeyInfo.GetEncryptedData();
+        }
+
+        /// <summary>
+        /// Return a binary ASN.1 encoding of the EncryptedPrivateKeyInfo structure in this object.
+        /// </summary>
+        /// <returns>A byte array containing the encoded object.</returns>
+        public byte[] GetEncoded()
+        {
+            return encryptedPrivateKeyInfo.GetEncoded();
+        }
+
+        /// <summary>
+        /// Get a decryptor from the passed in provider and decrypt the encrypted private key info, returning the result.
+        /// </summary>
+        /// <param name="inputDecryptorProvider">A provider to query for decryptors for the object.</param>
+        /// <returns>The decrypted private key info structure.</returns>
+        public PrivateKeyInfo DecryptPrivateKeyInfo(IDecryptorBuilderProvider inputDecryptorProvider)
+        {
+            try
+            {
+                ICipherBuilder decryptorBuilder = inputDecryptorProvider.CreateDecryptorBuilder(encryptedPrivateKeyInfo.EncryptionAlgorithm);
+
+                ICipher encIn = decryptorBuilder.BuildCipher(new MemoryInputStream(encryptedPrivateKeyInfo.GetEncryptedData()));
+
+                using (Stream strm = encIn.Stream)
+                {
+                    byte[] data = Streams.ReadAll(encIn.Stream);
+           
+                    return PrivateKeyInfo.GetInstance(data);
+                }
+            }
+            catch (Exception e)
+            {
+                throw new PkcsException("unable to read encrypted data: " + e.Message, e);
+            }
+        }
+    }
+}
diff --git a/crypto/src/pkcs/Pkcs8EncryptedPrivateKeyInfoBuilder.cs b/crypto/src/pkcs/Pkcs8EncryptedPrivateKeyInfoBuilder.cs
new file mode 100644
index 000000000..3b05deea7
--- /dev/null
+++ b/crypto/src/pkcs/Pkcs8EncryptedPrivateKeyInfoBuilder.cs
@@ -0,0 +1,52 @@
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Utilities.IO;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+namespace Org.BouncyCastle.Pkcs
+{
+    public class Pkcs8EncryptedPrivateKeyInfoBuilder
+    {
+        private PrivateKeyInfo privateKeyInfo;
+
+        public Pkcs8EncryptedPrivateKeyInfoBuilder(byte[] privateKeyInfo):  this(PrivateKeyInfo.GetInstance(privateKeyInfo))
+        {
+        }
+
+        public Pkcs8EncryptedPrivateKeyInfoBuilder(PrivateKeyInfo privateKeyInfo)
+        {
+            this.privateKeyInfo = privateKeyInfo;
+        }
+
+        /// <summary>
+        /// Create the encrypted private key info using the passed in encryptor.
+        /// </summary>
+        /// <param name="encryptor">The encryptor to use.</param>
+        /// <returns>An encrypted private key info containing the original private key info.</returns>
+        public Pkcs8EncryptedPrivateKeyInfo Build(
+            ICipherBuilder encryptor)
+        {
+            try
+            {
+                MemoryStream bOut = new MemoryOutputStream();
+                ICipher cOut = encryptor.BuildCipher(bOut);
+                byte[] keyData = privateKeyInfo.GetEncoded();
+
+                using (var str = cOut.Stream)
+                {
+                    str.Write(keyData, 0, keyData.Length);
+                }
+
+                return new Pkcs8EncryptedPrivateKeyInfo(new EncryptedPrivateKeyInfo((AlgorithmIdentifier)encryptor.AlgorithmDetails, bOut.ToArray()));
+            }
+            catch (IOException)
+            {
+                throw new InvalidOperationException("cannot encode privateKeyInfo");
+            }
+        }
+    }
+}
diff --git a/crypto/src/pkcs/PkcsException.cs b/crypto/src/pkcs/PkcsException.cs
new file mode 100644
index 000000000..f82d36724
--- /dev/null
+++ b/crypto/src/pkcs/PkcsException.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Pkcs
+{
+    /// <summary>
+    /// Base exception for PKCS related issues.
+    /// </summary>
+    public class PkcsException : Exception
+    {
+        public PkcsException(String message) : base(message)
+        {
+        }
+
+        public PkcsException(String message, Exception underlying) : base(message, underlying)
+        {
+        }
+    }
+}
diff --git a/crypto/src/pkcs/PkcsIOException.cs b/crypto/src/pkcs/PkcsIOException.cs
new file mode 100644
index 000000000..19f17a394
--- /dev/null
+++ b/crypto/src/pkcs/PkcsIOException.cs
@@ -0,0 +1,19 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Pkcs
+{
+    /// <summary>
+    /// Base exception for parsing related issues in the PKCS namespace.
+    /// </summary>
+    public class PkcsIOException: IOException
+    {
+        public PkcsIOException(String message) : base(message)
+        {
+        }
+
+        public PkcsIOException(String message, Exception underlying) : base(message, underlying)
+        {
+        }
+    }
+}
diff --git a/crypto/src/util/io/MemoryInputStream.cs b/crypto/src/util/io/MemoryInputStream.cs
new file mode 100644
index 000000000..d353314ee
--- /dev/null
+++ b/crypto/src/util/io/MemoryInputStream.cs
@@ -0,0 +1,13 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+    public class MemoryInputStream : MemoryStream
+    {
+        public MemoryInputStream(byte[] buffer) : base(buffer, false)
+        {
+        }
+
+        public sealed override bool CanWrite { get { return false; } }
+    }
+}
diff --git a/crypto/src/util/io/MemoryOutputStream.cs b/crypto/src/util/io/MemoryOutputStream.cs
new file mode 100644
index 000000000..a6de64680
--- /dev/null
+++ b/crypto/src/util/io/MemoryOutputStream.cs
@@ -0,0 +1,10 @@
+
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+    public class MemoryOutputStream: MemoryStream
+    {
+        public sealed override bool CanRead { get { return false; } }
+    }
+}