summary refs log tree commit diff
path: root/Crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs')
-rw-r--r--Crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs275
1 files changed, 275 insertions, 0 deletions
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();
+                }
+            }
+		}
+	}
+}