summary refs log tree commit diff
path: root/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs')
-rw-r--r--crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs281
1 files changed, 281 insertions, 0 deletions
diff --git a/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs b/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs
new file mode 100644
index 000000000..a63ea7b7f
--- /dev/null
+++ b/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs
@@ -0,0 +1,281 @@
+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);
+			}
+
+			public override void Close()
+			{
+				_out.Close();
+
+				// 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.Close();
+			}
+		}
+	}
+}