protected virtual ParametersWithIV CreateParametersWithIV(KeyParameter key,
			byte[] buf, ref int off, int len)
		{
			ParametersWithIV ivParams = new ParametersWithIV(key, buf, off, len);
			off += len;
			return ivParams;
		}
		public void Init(
			bool				forWrapping,
			ICipherParameters	parameters)
		{
			this.forWrapping = forWrapping;

			if (parameters is ParametersWithRandom)
			{
				parameters = ((ParametersWithRandom) parameters).Parameters;
			}

			if (parameters is KeyParameter)
			{
				this.param = (KeyParameter) parameters;
			}
			else if (parameters is ParametersWithIV)
			{
				ParametersWithIV pIV = (ParametersWithIV) parameters;
				byte[] iv = pIV.GetIV();

				if (iv.Length != 8)
					throw new ArgumentException("IV length not equal to 8", "parameters");

				this.iv = iv;
				this.param = (KeyParameter) pIV.Parameters;
			}
			else
			{
				// TODO Throw an exception for bad parameters?
			}
		}
		public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
		{
			byte[] keyBytes = contentEncryptionKey.GetKey();

			string rfc3211WrapperName = Helper.GetRfc3211WrapperName(keyEncryptionKeyOID);
			IWrapper keyWrapper = Helper.CreateWrapper(rfc3211WrapperName);

			// Note: In Java build, the IV is automatically generated in JCE layer
			int ivLength = rfc3211WrapperName.StartsWith("DESEDE") ? 8 : 16;
			byte[] iv = new byte[ivLength];
			random.NextBytes(iv);

			ICipherParameters parameters = new ParametersWithIV(keyEncryptionKey, iv);
			keyWrapper.Init(true, new ParametersWithRandom(parameters, random));
        	Asn1OctetString encryptedKey = new DerOctetString(
				keyWrapper.Wrap(keyBytes, 0, keyBytes.Length));

			DerSequence seq = new DerSequence(
				new DerObjectIdentifier(keyEncryptionKeyOID),
				new DerOctetString(iv));

			AlgorithmIdentifier keyEncryptionAlgorithm = new AlgorithmIdentifier(
				PkcsObjectIdentifiers.IdAlgPwriKek, seq);

			return new RecipientInfo(new PasswordRecipientInfo(
				keyDerivationAlgorithm, keyEncryptionAlgorithm, encryptedKey));
		}
		/**
		 * Base constructor.
		 * 
		 * @param key key to be used by underlying cipher
		 * @param macSize macSize in bits
		 * @param nonce nonce to be used
		 * @param associatedText associated text, if any
		 */
		public CcmParameters(
			KeyParameter	key,
			int				macSize,
			byte[]			nonce,
			byte[]			associatedText)
			: base(key, macSize, nonce, associatedText)
		{
		}
 internal PbeMethod(
     SymmetricKeyAlgorithmTag  encAlgorithm,
     S2k                       s2k,
     KeyParameter              key)
 {
     this.encAlgorithm = encAlgorithm;
     this.s2k = s2k;
     this.key = key;
 }
		/**
		 * Base constructor.
		 *
		 * @param key key to be used by underlying cipher
		 * @param macSize macSize in bits
		 * @param nonce nonce to be used
		 * @param associatedText associated text, if any
		 */
		public AeadParameters(
			KeyParameter	key,
			int				macSize,
			byte[]			nonce,
			byte[]			associatedText)
		{
			this.key = key;
			this.nonce = nonce;
			this.macSize = macSize;
			this.associatedText = associatedText;
		}
Example #7
0
		/**
		* Generate a new instance of an TlsMac.
		*
		* @param digest    The digest to use.
		* @param key_block A byte-array where the key for this mac is located.
		* @param offset    The number of bytes to skip, before the key starts in the buffer.
		* @param len       The length of the key.
		*/
		public TlsMac(
			IDigest	digest,
			byte[]	key_block,
			int		offset,
			int		len)
		{
			this.mac = new HMac(digest);
			KeyParameter param = new KeyParameter(key_block, offset, len);
			this.mac.Init(param);
			this.seqNo = 0;
		}
		public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
		{
			byte[] keyBytes = contentEncryptionKey.GetKey();

			IWrapper keyWrapper = Helper.CreateWrapper(keyEncryptionAlgorithm.ObjectID.Id);
			keyWrapper.Init(true, new ParametersWithRandom(keyEncryptionKey, random));
        	Asn1OctetString encryptedKey = new DerOctetString(
				keyWrapper.Wrap(keyBytes, 0, keyBytes.Length));

			return new RecipientInfo(new KekRecipientInfo(kekIdentifier, keyEncryptionAlgorithm, encryptedKey));
		}
		internal CmsTypedStream GetContentFromSessionKey(
			KeyParameter sKey)
		{
			ICmsReadable readable = secureReadable.GetReadable(sKey); 

			try
			{
				return new CmsTypedStream(readable.GetInputStream());
			}
			catch (IOException e)
			{
				throw new CmsException("error getting .", e);
			}
		}
		/**
        * Method init
        *
        * @param forWrapping
        * @param param
        */
        public void Init(
			bool				forWrapping,
			ICipherParameters	parameters)
        {
            this.forWrapping = forWrapping;
            this.engine = new CbcBlockCipher(new DesEdeEngine());

			SecureRandom sr;
			if (parameters is ParametersWithRandom)
			{
				ParametersWithRandom pr = (ParametersWithRandom) parameters;
				parameters = pr.Parameters;
				sr = pr.Random;
			}
			else
			{
				sr = new SecureRandom();
			}

			if (parameters is KeyParameter)
            {
                this.param = (KeyParameter) parameters;
                if (this.forWrapping)
				{
                    // Hm, we have no IV but we want to wrap ?!?
                    // well, then we have to create our own IV.
                    this.iv = new byte[8];
					sr.NextBytes(iv);

					this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
                }
            }
            else if (parameters is ParametersWithIV)
            {
				if (!forWrapping)
					throw new ArgumentException("You should not supply an IV for unwrapping");

				this.paramPlusIV = (ParametersWithIV) parameters;
                this.iv = this.paramPlusIV.GetIV();
                this.param = (KeyParameter) this.paramPlusIV.Parameters;

				if (this.iv.Length != 8)
					throw new ArgumentException("IV is not 8 octets", "parameters");
            }
        }
		private void F(
			byte[]  P,
			byte[]  S,
			int     c,
			byte[]  iBuf,
			byte[]  outBytes,
			int     outOff)
		{
			byte[]              state = new byte[hMac.GetMacSize()];
			ICipherParameters    param = new KeyParameter(P);

			hMac.Init(param);

			if (S != null)
			{
				hMac.BlockUpdate(S, 0, S.Length);
			}

			hMac.BlockUpdate(iBuf, 0, iBuf.Length);

			hMac.DoFinal(state, 0);

			Array.Copy(state, 0, outBytes, outOff, state.Length);

			for (int count = 1; count != c; count++)
			{
				hMac.Init(param);
				hMac.BlockUpdate(state, 0, state.Length);
				hMac.DoFinal(state, 0);

				for (int j = 0; j != state.Length; j++)
				{
					outBytes[outOff + j] ^= state[j];
				}
			}
		}
		public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
		{
			byte[] keyBytes = contentEncryptionKey.GetKey();
			AlgorithmIdentifier keyEncryptionAlgorithm = info.AlgorithmID;

			IWrapper keyWrapper = Helper.CreateWrapper(keyEncryptionAlgorithm.ObjectID.Id);
			keyWrapper.Init(true, new ParametersWithRandom(recipientPublicKey, random));
			byte[] encryptedKeyBytes = keyWrapper.Wrap(keyBytes, 0, keyBytes.Length);

			RecipientIdentifier recipId;
			if (recipientTbsCert != null)
			{
				IssuerAndSerialNumber issuerAndSerial = new IssuerAndSerialNumber(
					recipientTbsCert.Issuer, recipientTbsCert.SerialNumber.Value);
				recipId = new RecipientIdentifier(issuerAndSerial);
			}
			else
			{
				recipId = new RecipientIdentifier(subjectKeyIdentifier);
			}

			return new RecipientInfo(new KeyTransRecipientInfo(recipId, keyEncryptionAlgorithm,
				new DerOctetString(encryptedKeyBytes)));
		}
        protected internal virtual AlgorithmIdentifier GetAlgorithmIdentifier(
			string					encryptionOid,
			KeyParameter			encKey,
			Asn1Encodable			asn1Params,
			out ICipherParameters	cipherParameters)
		{
			Asn1Object asn1Object;
			if (asn1Params != null)
			{
				asn1Object = asn1Params.ToAsn1Object();
				cipherParameters = ParameterUtilities.GetCipherParameters(
					encryptionOid, encKey, asn1Object);
			}
			else
			{
				asn1Object = DerNull.Instance;
				cipherParameters = encKey;
			}

			return new AlgorithmIdentifier(
				new DerObjectIdentifier(encryptionOid),
				asn1Object);
		}
		/**
		* add a KEK recipient.
		* @param key the secret key to use for wrapping
		* @param keyIdentifier the byte string that identifies the key
		*/
		public void AddKekRecipient(
			string			keyAlgorithm, // TODO Remove need for this parameter
			KeyParameter	key,
			KekIdentifier	kekIdentifier)
		{
			KekRecipientInfoGenerator kekrig = new KekRecipientInfoGenerator();
			kekrig.KekIdentifier = kekIdentifier;
			kekrig.KeyEncryptionKeyOID = keyAlgorithm;
			kekrig.KeyEncryptionKey = key;

			recipientInfoGenerators.Add(kekrig);
		}
		/**
		 * add a KEK recipient.
		 * @param key the secret key to use for wrapping
		 * @param keyIdentifier the byte string that identifies the key
		 */
		public void AddKekRecipient(
			string			keyAlgorithm, // TODO Remove need for this parameter
			KeyParameter	key,
			byte[]			keyIdentifier)
		{
			AddKekRecipient(keyAlgorithm, key, new KekIdentifier(keyIdentifier, null, null));
		}
			public ICmsReadable GetReadable(KeyParameter key)
			{
				// TODO Create AEAD cipher instance to decrypt and calculate tag ( MAC)
				throw new CmsException("AuthEnveloped data decryption not yet implemented");

//				RFC 5084 ASN.1 Module
//				-- Parameters for AlgorithmIdentifier
//				
//				CCMParameters ::= SEQUENCE {
//				  aes-nonce         OCTET STRING (SIZE(7..13)),
//				  aes-ICVlen        AES-CCM-ICVlen DEFAULT 12 }
//				
//				AES-CCM-ICVlen ::= INTEGER (4 | 6 | 8 | 10 | 12 | 14 | 16)
//				
//				GCMParameters ::= SEQUENCE {
//				  aes-nonce        OCTET STRING, -- recommended size is 12 octets
//				  aes-ICVlen       AES-GCM-ICVlen DEFAULT 12 }
//				
//				AES-GCM-ICVlen ::= INTEGER (12 | 13 | 14 | 15 | 16)
			}            
		public void Init(
			ICipherParameters parameters)
		{
			Reset();

			if (!(parameters is KeyParameter || parameters is ParametersWithIV))
				throw new ArgumentException("parameters must be an instance of KeyParameter or ParametersWithIV");

			// KeyParameter must contain a double or triple length DES key,
			// however the underlying cipher is a single DES. The middle and
			// right key are used only in the final step.

			KeyParameter kp;
			if (parameters is KeyParameter)
			{
				kp = (KeyParameter)parameters;
			}
			else
			{
				kp = (KeyParameter)((ParametersWithIV)parameters).Parameters;
			}

			KeyParameter key1;
			byte[] keyvalue = kp.GetKey();

			if (keyvalue.Length == 16)
			{ // Double length DES key
				key1 = new KeyParameter(keyvalue, 0, 8);
				this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
				this.lastKey3 = key1;
			}
			else if (keyvalue.Length == 24)
			{ // Triple length DES key
				key1 = new KeyParameter(keyvalue, 0, 8);
				this.lastKey2 = new KeyParameter(keyvalue, 8, 8);
				this.lastKey3 = new KeyParameter(keyvalue, 16, 8);
			}
			else
			{
				throw new ArgumentException("Key must be either 112 or 168 bit long");
			}

			if (parameters is ParametersWithIV)
			{
				cipher.Init(true, new ParametersWithIV(key1, ((ParametersWithIV)parameters).GetIV()));
			}
			else
			{
				cipher.Init(true, key1);
			}
		}
Example #18
0
        private byte[] EncryptBlock(
            byte[]  input,
            int     inOff,
            int     inLen,
            byte[]  z)
        {
            byte[]          C = null;
            KeyParameter    macKey = null;
            KdfParameters   kParam = new KdfParameters(z, param.GetDerivationV());
            int             c_text_length = 0;
            int             macKeySize = param.MacKeySize;

            if (cipher == null)     // stream mode
            {
				byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));

                C = new byte[inLen + mac.GetMacSize()];
                c_text_length = inLen;

				for (int i = 0; i != inLen; i++)
                {
                    C[i] = (byte)(input[inOff + i] ^ Buffer[i]);
                }

                macKey = new KeyParameter(Buffer, inLen, (macKeySize / 8));
            }
            else
            {
                int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize;
				byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));

                cipher.Init(true, new KeyParameter(Buffer, 0, (cipherKeySize / 8)));

                c_text_length = cipher.GetOutputSize(inLen);
				byte[] tmp = new byte[c_text_length];

				int len = cipher.ProcessBytes(input, inOff, inLen, tmp, 0);
				len += cipher.DoFinal(tmp, len);

				C = new byte[len + mac.GetMacSize()];
				c_text_length = len;

				Array.Copy(tmp, 0, C, 0, len);

				macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
            }

            byte[] macIV = param.GetEncodingV();

            mac.Init(macKey);
            mac.BlockUpdate(C, 0, c_text_length);
            mac.BlockUpdate(macIV, 0, macIV.Length);
            //
            // return the message and it's MAC
            //
            mac.DoFinal(C, c_text_length);
            return C;
        }
		public virtual void Init(
			bool				forEncryption,
			ICipherParameters	parameters)
		{
			this.forEncryption = forEncryption;
			this.macBlock = null;

			if (parameters is AeadParameters)
			{
				AeadParameters param = (AeadParameters)parameters;

				nonce = param.GetNonce();
				A = param.GetAssociatedText();

				int macSizeBits = param.MacSize;
	            if (macSizeBits < 96 || macSizeBits > 128 || macSizeBits % 8 != 0)
	            {
	                throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
	            }

	            macSize = macSizeBits / 8; 
				keyParam = param.Key;
			}
			else if (parameters is ParametersWithIV)
			{
				ParametersWithIV param = (ParametersWithIV)parameters;

				nonce = param.GetIV();
				A = null;
	            macSize = 16; 
				keyParam = (KeyParameter)param.Parameters;
			}
			else
			{
				throw new ArgumentException("invalid parameters passed to GCM");
			}

			int bufLength = forEncryption ? BlockSize : (BlockSize + macSize);
			this.bufBlock = new byte[bufLength];

			if (nonce == null || nonce.Length < 1)
			{
				throw new ArgumentException("IV must be at least 1 byte");
			}

			if (A == null)
			{
				// Avoid lots of null checks
				A = new byte[0];
			}

			// Cipher always used in forward mode
			cipher.Init(true, keyParam);

			// TODO This should be configurable by Init parameters
			// (but must be 16 if nonce length not 12) (BlockSize?)
//			this.tagLength = 16;

			this.H = new byte[BlockSize];
			cipher.ProcessBlock(H, 0, H, 0);
			multiplier.Init(H);

			this.initS = gHASH(A);

			if (nonce.Length == 12)
			{
				this.J0 = new byte[16];
				Array.Copy(nonce, 0, J0, 0, nonce.Length);
				this.J0[15] = 0x01;
			}
			else
			{
				this.J0 = gHASH(nonce);
				byte[] X = new byte[16];
				packLength((ulong)nonce.Length * 8UL, X, 8);
				GcmUtilities.Xor(this.J0, X);
				multiplier.MultiplyH(this.J0);
			}

			this.S = Arrays.Clone(initS);
			this.counter = Arrays.Clone(J0);
			this.bufOff = 0;
			this.totalLength = 0;
		}
Example #20
0
        private byte[] DecryptBlock(
            byte[]  in_enc,
            int     inOff,
            int     inLen,
            byte[]  z)
        {
            byte[]          M = null;
            KeyParameter    macKey = null;
            KdfParameters   kParam = new KdfParameters(z, param.GetDerivationV());
            int             macKeySize = param.MacKeySize;

            kdf.Init(kParam);

            inLen -= mac.GetMacSize();

            if (cipher == null)     // stream mode
            {
				byte[] Buffer = GenerateKdfBytes(kParam, inLen + (macKeySize / 8));

                M = new byte[inLen];

                for (int i = 0; i != inLen; i++)
                {
                    M[i] = (byte)(in_enc[inOff + i] ^ Buffer[i]);
                }

                macKey = new KeyParameter(Buffer, inLen, (macKeySize / 8));
            }
            else
            {
                int cipherKeySize = ((IesWithCipherParameters)param).CipherKeySize;
				byte[] Buffer = GenerateKdfBytes(kParam, (cipherKeySize / 8) + (macKeySize / 8));

                cipher.Init(false, new KeyParameter(Buffer, 0, (cipherKeySize / 8)));

				M = cipher.DoFinal(in_enc, inOff, inLen);

				macKey = new KeyParameter(Buffer, (cipherKeySize / 8), (macKeySize / 8));
            }

            byte[] macIV = param.GetEncodingV();

            mac.Init(macKey);
            mac.BlockUpdate(in_enc, inOff, inLen);
            mac.BlockUpdate(macIV, 0, macIV.Length);
            mac.DoFinal(macBuf, 0);

			inOff += inLen;

			for (int t = 0; t < macBuf.Length; t++)
            {
                if (macBuf[t] != in_enc[inOff + t])
                {
                    throw (new InvalidCipherTextException("IMac codes failed to equal."));
                }
            }

            return M;
        }
        protected virtual KeyParameter CreateKeyParameter(byte[] buf, ref int off, int len)
		{
			KeyParameter key = new KeyParameter(buf, off, len);
			off += len;
			return key;
		}
Example #22
0
		private static void hmac_hash(IDigest digest, byte[] secret, byte[] seed, byte[] output)
		{
			HMac mac = new HMac(digest);
			KeyParameter param = new KeyParameter(secret);
			byte[] a = seed;
			int size = digest.GetDigestSize();
			int iterations = (output.Length + size - 1) / size;
			byte[] buf = new byte[mac.GetMacSize()];
			byte[] buf2 = new byte[mac.GetMacSize()];
			for (int i = 0; i < iterations; i++)
			{
				mac.Init(param);
				mac.BlockUpdate(a, 0, a.Length);
				mac.DoFinal(buf, 0);
				a = buf;
				mac.Init(param);
				mac.BlockUpdate(a, 0, a.Length);
				mac.BlockUpdate(seed, 0, seed.Length);
				mac.DoFinal(buf2, 0);
				Array.Copy(buf2, 0, output, (size * i), System.Math.Min(size, output.Length - (size * i)));
			}
		}
		private KeyParameter UnwrapSessionKey(
			string			wrapAlg,
			KeyParameter	agreedKey)
		{
			byte[] encKeyOctets = encryptedKey.GetOctets();

			IWrapper keyCipher = WrapperUtilities.GetWrapper(wrapAlg);
			keyCipher.Init(false, agreedKey);
			byte[] sKeyBytes = keyCipher.Unwrap(encKeyOctets, 0, encKeyOctets.Length);
			return ParameterUtilities.CreateKeyParameter(GetContentAlgorithmName(), sKeyBytes);
		}
			public ICmsReadable GetReadable(KeyParameter sKey)
			{
				string macAlg = this.algorithm.ObjectID.Id;
//				Asn1Object sParams = this.algorithm.Parameters.ToAsn1Object();

				try
				{
					this.mac = MacUtilities.GetMac(macAlg);

					// FIXME Support for MAC algorithm parameters similar to cipher parameters
//						ASN1Object sParams = (ASN1Object)macAlg.getParameters();
//
//						if (sParams != null && !(sParams instanceof ASN1Null))
//						{
//							AlgorithmParameters params = CMSEnvelopedHelper.INSTANCE.createAlgorithmParameters(macAlg.getObjectId().getId(), provider);
//
//							params.init(sParams.getEncoded(), "ASN.1");
//
//							mac.init(sKey, params.getParameterSpec(IvParameterSpec.class));
//						}
//						else
					{
						mac.Init(sKey);
					}

//						Asn1Object asn1Params = asn1Enc == null ? null : asn1Enc.ToAsn1Object();
//
//						ICipherParameters cipherParameters = sKey;
//
//						if (asn1Params != null && !(asn1Params is Asn1Null))
//						{
//							cipherParameters = ParameterUtilities.GetCipherParameters(
//							macAlg.ObjectID, cipherParameters, asn1Params);
//						}
//						else
//						{
//							string alg = macAlg.ObjectID.Id;
//							if (alg.Equals(CmsEnvelopedDataGenerator.DesEde3Cbc)
//								|| alg.Equals(CmsEnvelopedDataGenerator.IdeaCbc)
//								|| alg.Equals(CmsEnvelopedDataGenerator.Cast5Cbc))
//							{
//								cipherParameters = new ParametersWithIV(cipherParameters, new byte[8]);
//							}
//						}
//
//						mac.Init(cipherParameters);
				}
				catch (SecurityUtilityException e)
				{
					throw new CmsException("couldn't create cipher.", e);
				}
				catch (InvalidKeyException e)
				{
					throw new CmsException("key invalid in message.", e);
				}
				catch (IOException e)
				{
					throw new CmsException("error decoding algorithm parameters.", e);
				}

				try
				{
					return new CmsProcessableInputStream(
						new TeeInputStream(
							readable.GetInputStream(),
							new MacOutputStream(this.mac)));
				}
				catch (IOException e)
				{
					throw new CmsException("error reading content.", e);
				}
			}
		private static AlgorithmIdentifier DetermineKeyEncAlg(
			string algorithm, KeyParameter key)
		{
			if (algorithm.StartsWith("DES"))
			{
				return new AlgorithmIdentifier(
					PkcsObjectIdentifiers.IdAlgCms3DesWrap,
					DerNull.Instance);
			}
			else if (algorithm.StartsWith("RC2"))
			{
				return new AlgorithmIdentifier(
					PkcsObjectIdentifiers.IdAlgCmsRC2Wrap,
					new DerInteger(58));
			}
			else if (algorithm.StartsWith("AES"))
			{
				int length = key.GetKey().Length * 8;
				DerObjectIdentifier wrapOid;

				if (length == 128)
				{
					wrapOid = NistObjectIdentifiers.IdAes128Wrap;
				}
				else if (length == 192)
				{
					wrapOid = NistObjectIdentifiers.IdAes192Wrap;
				}
				else if (length == 256)
				{
					wrapOid = NistObjectIdentifiers.IdAes256Wrap;
				}
				else
				{
					throw new ArgumentException("illegal keysize in AES");
				}

				return new AlgorithmIdentifier(wrapOid);  // parameters absent
			}
			else if (algorithm.StartsWith("SEED"))
			{
				// parameters absent
				return new AlgorithmIdentifier(KisaObjectIdentifiers.IdNpkiAppCmsSeedWrap);
			}
			else if (algorithm.StartsWith("CAMELLIA"))
			{
				int length = key.GetKey().Length * 8;
				DerObjectIdentifier wrapOid;

				if (length == 128)
				{
					wrapOid = NttObjectIdentifiers.IdCamellia128Wrap;
				}
				else if (length == 192)
				{
					wrapOid = NttObjectIdentifiers.IdCamellia192Wrap;
				}
				else if (length == 256)
				{
					wrapOid = NttObjectIdentifiers.IdCamellia256Wrap;
				}
				else
				{
					throw new ArgumentException("illegal keysize in Camellia");
				}

				return new AlgorithmIdentifier(wrapOid); // parameters must be absent
			}
			else
			{
				throw new ArgumentException("unknown algorithm");
			}
		}
			public ICmsReadable GetReadable(KeyParameter sKey)
			{
				try
				{
					this.cipher =  CipherUtilities.GetCipher(this.algorithm.ObjectID);

					Asn1Encodable asn1Enc = this.algorithm.Parameters;
					Asn1Object asn1Params = asn1Enc == null ? null : asn1Enc.ToAsn1Object();

					ICipherParameters cipherParameters = sKey;

					if (asn1Params != null && !(asn1Params is Asn1Null))
					{
						cipherParameters = ParameterUtilities.GetCipherParameters(
							this.algorithm.ObjectID, cipherParameters, asn1Params);
					}
					else
					{
						string alg = this.algorithm.ObjectID.Id;
						if (alg.Equals(CmsEnvelopedDataGenerator.DesEde3Cbc)
							|| alg.Equals(CmsEnvelopedDataGenerator.IdeaCbc)
							|| alg.Equals(CmsEnvelopedDataGenerator.Cast5Cbc))
						{
							cipherParameters = new ParametersWithIV(cipherParameters, new byte[8]);
						}
					}

					cipher.Init(false, cipherParameters);
				}
				catch (SecurityUtilityException e)
				{
					throw new CmsException("couldn't create cipher.", e);
				}
				catch (InvalidKeyException e)
				{
					throw new CmsException("key invalid in message.", e);
				}
				catch (IOException e)
				{
					throw new CmsException("error decoding algorithm parameters.", e);
				}

				try
				{
					return new CmsProcessableInputStream(
						new CipherStream(readable.GetInputStream(), cipher, null));
				}
				catch (IOException e)
				{
					throw new CmsException("error reading content.", e);
				}
			}
		public RecipientInfo Generate(KeyParameter contentEncryptionKey, SecureRandom random)
		{
			byte[] keyBytes = contentEncryptionKey.GetKey();

			AsymmetricKeyParameter senderPublicKey = senderKeyPair.Public;
			ICipherParameters senderPrivateParams = senderKeyPair.Private;


			OriginatorIdentifierOrKey originator;
			try
			{
				originator = new OriginatorIdentifierOrKey(
					CreateOriginatorPublicKey(senderPublicKey));
			}
			catch (IOException e)
			{
				throw new InvalidKeyException("cannot extract originator public key: " + e);
			}


			Asn1OctetString ukm = null;
			if (keyAgreementOID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
			{
				try
				{
					IAsymmetricCipherKeyPairGenerator ephemKPG =
						GeneratorUtilities.GetKeyPairGenerator(keyAgreementOID);
					ephemKPG.Init(
						((ECPublicKeyParameters)senderPublicKey).CreateKeyGenerationParameters(random));

					AsymmetricCipherKeyPair ephemKP = ephemKPG.GenerateKeyPair();

					ukm = new DerOctetString(
						new MQVuserKeyingMaterial(
							CreateOriginatorPublicKey(ephemKP.Public), null));

					senderPrivateParams = new MqvPrivateParameters(
						(ECPrivateKeyParameters)senderPrivateParams,
						(ECPrivateKeyParameters)ephemKP.Private,
						(ECPublicKeyParameters)ephemKP.Public);
				}
				catch (IOException e)
				{
					throw new InvalidKeyException("cannot extract MQV ephemeral public key: " + e);
				}
				catch (SecurityUtilityException e)
				{
					throw new InvalidKeyException("cannot determine MQV ephemeral key pair parameters from public key: " + e);
				}
			}


			DerSequence paramSeq = new DerSequence(
				keyEncryptionOID,
				DerNull.Instance);
			AlgorithmIdentifier keyEncAlg = new AlgorithmIdentifier(keyAgreementOID, paramSeq);


			Asn1EncodableVector recipientEncryptedKeys = new Asn1EncodableVector();
			foreach (X509Certificate recipientCert in recipientCerts)
			{
				TbsCertificateStructure tbsCert;
				try
				{
					tbsCert = TbsCertificateStructure.GetInstance(
						Asn1Object.FromByteArray(recipientCert.GetTbsCertificate()));
				}
				catch (Exception)
				{
					throw new ArgumentException("can't extract TBS structure from certificate");
				}

				// TODO Should there be a SubjectKeyIdentifier-based alternative?
				IssuerAndSerialNumber issuerSerial = new IssuerAndSerialNumber(
					tbsCert.Issuer, tbsCert.SerialNumber.Value);
				KeyAgreeRecipientIdentifier karid = new KeyAgreeRecipientIdentifier(issuerSerial);

				ICipherParameters recipientPublicParams = recipientCert.GetPublicKey();
				if (keyAgreementOID.Id.Equals(CmsEnvelopedGenerator.ECMqvSha1Kdf))
				{
					recipientPublicParams = new MqvPublicParameters(
						(ECPublicKeyParameters)recipientPublicParams,
						(ECPublicKeyParameters)recipientPublicParams);
				}

				// Use key agreement to choose a wrap key for this recipient
				IBasicAgreement keyAgreement = AgreementUtilities.GetBasicAgreementWithKdf(
					keyAgreementOID, keyEncryptionOID.Id);
				keyAgreement.Init(new ParametersWithRandom(senderPrivateParams, random));
				BigInteger agreedValue = keyAgreement.CalculateAgreement(recipientPublicParams);

				int keyEncryptionKeySize = GeneratorUtilities.GetDefaultKeySize(keyEncryptionOID) / 8;
				byte[] keyEncryptionKeyBytes = X9IntegerConverter.IntegerToBytes(agreedValue, keyEncryptionKeySize);
				KeyParameter keyEncryptionKey = ParameterUtilities.CreateKeyParameter(
					keyEncryptionOID, keyEncryptionKeyBytes);

				// Wrap the content encryption key with the agreement key
				IWrapper keyWrapper = Helper.CreateWrapper(keyEncryptionOID.Id);
				keyWrapper.Init(true, new ParametersWithRandom(keyEncryptionKey, random));
				byte[] encryptedKeyBytes = keyWrapper.Wrap(keyBytes, 0, keyBytes.Length);

	        	Asn1OctetString encryptedKey = new DerOctetString(encryptedKeyBytes);

				recipientEncryptedKeys.Add(new RecipientEncryptedKey(karid, encryptedKey));
			}

			return new RecipientInfo(new KeyAgreeRecipientInfo(originator, ukm, keyEncAlg,
				new DerSequence(recipientEncryptedKeys)));
		}
		private byte[] CreateSessionInfo(
			SymmetricKeyAlgorithmTag	algorithm,
			KeyParameter				key)
		{
			byte[] keyBytes = key.GetKey();
			byte[] sessionInfo = new byte[keyBytes.Length + 3];
			sessionInfo[0] = (byte) algorithm;
			keyBytes.CopyTo(sessionInfo, 1);
			AddCheckSum(sessionInfo);
			return sessionInfo;
		}