EnvelopedPkcs7.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / clr / src / ManagedLibraries / Security / System / Security / Cryptography / Pkcs / EnvelopedPkcs7.cs / 5 / EnvelopedPkcs7.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 

// 
// EnvelopedPkcs7.cs 
//
 
namespace System.Security.Cryptography.Pkcs {
    using System.Collections;
    using System.Diagnostics;
    using System.Globalization; 
    using System.IO;
    using System.Runtime.InteropServices; 
    using System.Security.Cryptography; 
    using System.Security.Cryptography.X509Certificates;
    using System.Security.Cryptography.Xml; 
    using System.Security.Permissions;
    using System.Text;

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] 
    public sealed class EnvelopedCms {
        private SafeCryptMsgHandle               m_safeCryptMsgHandle; 
        private int                              m_version; 
        private SubjectIdentifierType            m_recipientIdentifierType;
        private ContentInfo                      m_contentInfo; 
        private AlgorithmIdentifier              m_encryptionAlgorithm;
        private X509Certificate2Collection       m_certificates;
        private CryptographicAttributeObjectCollection m_unprotectedAttributes;
 
        private struct CMSG_DECRYPT_PARAM {
            internal SafeCertContextHandle  safeCertContextHandle; 
            internal SafeCryptProvHandle    safeCryptProvHandle; 
            internal uint                   keySpec;
        } 

        private struct CMSG_ENCRYPT_PARAM {
            internal bool                            useCms;
            internal SafeCryptProvHandle             safeCryptProvHandle; 
            internal SafeLocalAllocHandle            pvEncryptionAuxInfo;
            internal SafeLocalAllocHandle            rgpRecipients; 
            internal SafeLocalAllocHandle            rgCertEncoded; 
            internal SafeLocalAllocHandle            rgUnprotectedAttr;
            internal SafeLocalAllocHandle[]          rgSubjectKeyIdentifier; 
            internal SafeLocalAllocHandle[]          rgszObjId;
            internal SafeLocalAllocHandle[]          rgszKeyWrapObjId;
            internal SafeLocalAllocHandle[]          rgKeyWrapAuxInfo;
            internal SafeLocalAllocHandle[]          rgEphemeralIdentifier; 
            internal SafeLocalAllocHandle[]          rgszEphemeralObjId;
            internal SafeLocalAllocHandle[]          rgUserKeyingMaterial; 
            internal SafeLocalAllocHandle[]          prgpEncryptedKey; 
            internal SafeLocalAllocHandle[]          rgpEncryptedKey;
        } 

        //
        // Constructors.
        // 

        public EnvelopedCms () : 
            this(SubjectIdentifierType.IssuerAndSerialNumber, new ContentInfo(CAPI.szOID_RSA_data, new byte[0]), new AlgorithmIdentifier(CAPI.szOID_RSA_DES_EDE3_CBC)) { 
        }
 
        public EnvelopedCms (ContentInfo contentInfo) :
            this(SubjectIdentifierType.IssuerAndSerialNumber, contentInfo, new AlgorithmIdentifier(CAPI.szOID_RSA_DES_EDE3_CBC)) {
        }
 
        public EnvelopedCms (SubjectIdentifierType recipientIdentifierType, ContentInfo contentInfo) :
            this(recipientIdentifierType, contentInfo, new AlgorithmIdentifier(CAPI.szOID_RSA_DES_EDE3_CBC)) { 
        } 

        public EnvelopedCms (ContentInfo contentInfo, AlgorithmIdentifier encryptionAlgorithm) : 
            this(SubjectIdentifierType.IssuerAndSerialNumber, contentInfo, encryptionAlgorithm) {
        }

        public EnvelopedCms (SubjectIdentifierType recipientIdentifierType, ContentInfo contentInfo, AlgorithmIdentifier encryptionAlgorithm) { 
            if (contentInfo == null)
                throw new ArgumentNullException("contentInfo"); 
            if (contentInfo.Content == null) 
                throw new ArgumentNullException("contentInfo.Content");
            if (encryptionAlgorithm == null) 
                throw new ArgumentNullException("encryptionAlgorithm");

            m_safeCryptMsgHandle = SafeCryptMsgHandle.InvalidHandle;
            m_version = recipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier ? 2 : 0; 
            m_recipientIdentifierType = recipientIdentifierType;
            m_contentInfo = contentInfo; 
            m_encryptionAlgorithm = encryptionAlgorithm; 
            m_encryptionAlgorithm.Parameters = new byte[0];
            m_certificates = new X509Certificate2Collection(); 
            m_unprotectedAttributes = new CryptographicAttributeObjectCollection();
        }

        // 
        // Public APIs.
        // 
 
        public int Version {
            get { 
                return m_version;
            }
        }
 
        public ContentInfo ContentInfo {
            get { 
                return m_contentInfo; 
            }
        } 

        public AlgorithmIdentifier ContentEncryptionAlgorithm {
            get {
                return m_encryptionAlgorithm; 
            }
        } 
 
        public X509Certificate2Collection Certificates {
            get { 
                return m_certificates;
            }
        }
 
        public CryptographicAttributeObjectCollection UnprotectedAttributes {
            get { 
                return m_unprotectedAttributes; 
            }
        } 

        public RecipientInfoCollection RecipientInfos {
            get {
                if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid) { 
                    return new RecipientInfoCollection();
                } 
                return new RecipientInfoCollection(m_safeCryptMsgHandle); 
            }
        } 

        public byte[] Encode () {
            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid)
                throw new InvalidOperationException(SecurityResources.GetResourceString("Cryptography_Cms_MessageNotEncrypted")); 

            return PkcsUtils.GetContent(m_safeCryptMsgHandle); 
        } 

        public void Decode (byte[] encodedMessage) { 
            if (encodedMessage == null)
                throw new ArgumentNullException("encodedMessage");

            if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid) { 
                m_safeCryptMsgHandle.Dispose();
            } 
 
            // Open to decode.
            m_safeCryptMsgHandle = OpenToDecode(encodedMessage); 

            // Get version.
            m_version = (int) PkcsUtils.GetVersion(m_safeCryptMsgHandle);
 
            // Get contentInfo (content still encrypted).
            Oid contentType = PkcsUtils.GetContentType(m_safeCryptMsgHandle); 
            byte[] content = PkcsUtils.GetContent(m_safeCryptMsgHandle); 
            m_contentInfo = new ContentInfo(contentType, content);
 
            // Get encryption algorithm.
            m_encryptionAlgorithm = PkcsUtils.GetAlgorithmIdentifier(m_safeCryptMsgHandle);

            // Get certificates. 
            m_certificates = PkcsUtils.GetCertificates(m_safeCryptMsgHandle);
 
            // Get unprotected attributes. 
            m_unprotectedAttributes = PkcsUtils.GetUnprotectedAttributes(m_safeCryptMsgHandle);
        } 

        public void Encrypt () {
            Encrypt(new CmsRecipientCollection());
        } 

        public void Encrypt (CmsRecipient recipient) { 
            if (recipient == null) 
                throw new ArgumentNullException("recipient");
 
            Encrypt(new CmsRecipientCollection(recipient));
        }

        public void Encrypt (CmsRecipientCollection recipients) { 
            if (recipients == null)
                throw new ArgumentNullException("recipients"); 
 
            if (ContentInfo.Content.Length == 0)
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Envelope_Empty_Content")); 

            if (recipients.Count == 0)
                recipients = PkcsUtils.SelectRecipients(m_recipientIdentifierType);
 
            EncryptContent(recipients);
        } 
 
        public void Decrypt () {
            DecryptContent(this.RecipientInfos, null); 
        }

        public void Decrypt (RecipientInfo recipientInfo) {
            if (recipientInfo == null) 
                throw new ArgumentNullException("recipientInfo");
 
            DecryptContent(new RecipientInfoCollection(recipientInfo), null); 
        }
 
        public void Decrypt (X509Certificate2Collection extraStore) {
            if (extraStore == null)
                throw new ArgumentNullException("extraStore");
 
            DecryptContent(this.RecipientInfos, extraStore);
        } 
 
        public void Decrypt (RecipientInfo recipientInfo, X509Certificate2Collection extraStore) {
            if (recipientInfo == null) 
                throw new ArgumentNullException("recipientInfo");

            if (extraStore == null)
                throw new ArgumentNullException("extraStore"); 

            DecryptContent(new RecipientInfoCollection(recipientInfo), extraStore); 
        } 

        // 
        // Private methods.
        //

        private unsafe void DecryptContent (RecipientInfoCollection recipientInfos, X509Certificate2Collection extraStore) { 
            int hr = CAPI.CRYPT_E_RECIPIENT_NOT_FOUND;
 
            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid) 
                throw new InvalidOperationException(SecurityResources.GetResourceString("Cryptography_Cms_NoEncryptedMessageToEncode"));
 
            for (int index = 0; index < recipientInfos.Count; index++) {
                RecipientInfo recipientInfo = recipientInfos[index];
                CMSG_DECRYPT_PARAM cmsgDecryptParam = new CMSG_DECRYPT_PARAM();
 
                // Get CSP parameters
                int hr2 = GetCspParams(recipientInfo, extraStore, ref cmsgDecryptParam); 
 
                if (hr2 == CAPI.S_OK) {
                    // 


                    CspParameters parameters = new CspParameters();
                    if (X509Utils.GetPrivateKeyInfo(cmsgDecryptParam.safeCertContextHandle, ref parameters) == false) 
                        throw new CryptographicException(Marshal.GetLastWin32Error());
 
                    KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags); 
                    KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Open | KeyContainerPermissionFlags.Decrypt);
                    kp.AccessEntries.Add(entry); 
                    kp.Demand();

                    // Decrypt the content.
                    switch (recipientInfo.Type) { 
                    case RecipientInfoType.KeyTransport:
                        CAPI.CMSG_CTRL_DECRYPT_PARA ctrlDecryptPara = new CAPI.CMSG_CTRL_DECRYPT_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_DECRYPT_PARA))); 
                        ctrlDecryptPara.hCryptProv = cmsgDecryptParam.safeCryptProvHandle.DangerousGetHandle(); 
                        ctrlDecryptPara.dwKeySpec = cmsgDecryptParam.keySpec;
                        ctrlDecryptPara.dwRecipientIndex = (uint) recipientInfo.Index; 

                        if (!CAPI.CryptMsgControl(m_safeCryptMsgHandle,
                                                  0,
                                                  CAPI.CMSG_CTRL_DECRYPT, 
                                                  new IntPtr(&ctrlDecryptPara)))
                            hr2 = Marshal.GetHRForLastWin32Error(); 
 
                        GC.KeepAlive(ctrlDecryptPara);
                        break; 

                    case RecipientInfoType.KeyAgreement:
                        SafeCertContextHandle pOriginatorCert = SafeCertContextHandle.InvalidHandle;
                        KeyAgreeRecipientInfo keyAgree = (KeyAgreeRecipientInfo) recipientInfo; 
                        CAPI.CMSG_CMS_RECIPIENT_INFO cmsRecipientInfo = (CAPI.CMSG_CMS_RECIPIENT_INFO) Marshal.PtrToStructure(keyAgree.pCmsgRecipientInfo.DangerousGetHandle(), typeof(CAPI.CMSG_CMS_RECIPIENT_INFO));
 
                        CAPI.CMSG_CTRL_KEY_AGREE_DECRYPT_PARA keyAgreeDecryptPara = new CAPI.CMSG_CTRL_KEY_AGREE_DECRYPT_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_KEY_AGREE_DECRYPT_PARA))); 
                        keyAgreeDecryptPara.hCryptProv = cmsgDecryptParam.safeCryptProvHandle.DangerousGetHandle();
                        keyAgreeDecryptPara.dwKeySpec = cmsgDecryptParam.keySpec; 
                        keyAgreeDecryptPara.pKeyAgree = cmsRecipientInfo.pRecipientInfo;
                        keyAgreeDecryptPara.dwRecipientIndex = keyAgree.Index;
                        keyAgreeDecryptPara.dwRecipientEncryptedKeyIndex = keyAgree.SubIndex;
 
                        if (keyAgree.SubType == RecipientSubType.CertIdKeyAgreement) {
                            CAPI.CMSG_KEY_AGREE_CERT_ID_RECIPIENT_INFO certIdKeyAgree = (CAPI.CMSG_KEY_AGREE_CERT_ID_RECIPIENT_INFO) keyAgree.CmsgRecipientInfo; 
                            SafeCertStoreHandle hCertStore = BuildOriginatorStore(this.Certificates, extraStore); 

                            pOriginatorCert = CAPI.CertFindCertificateInStore(hCertStore, 
                                                                              CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                                              0,
                                                                              CAPI.CERT_FIND_CERT_ID,
                                                                              new IntPtr(&certIdKeyAgree.OriginatorCertId), 
                                                                              SafeCertContextHandle.InvalidHandle);
                            if (pOriginatorCert == null || pOriginatorCert.IsInvalid) { 
                                hr2 = CAPI.CRYPT_E_NOT_FOUND; 
                                break;
                            } 

                            CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(pOriginatorCert.DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT));
                            CAPI.CERT_INFO certInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
                            keyAgreeDecryptPara.OriginatorPublicKey = certInfo.SubjectPublicKeyInfo.PublicKey; 
                        }
                        else { 
                            CAPI.CMSG_KEY_AGREE_PUBLIC_KEY_RECIPIENT_INFO publicKeyAgree = (CAPI.CMSG_KEY_AGREE_PUBLIC_KEY_RECIPIENT_INFO) keyAgree.CmsgRecipientInfo; 
                            keyAgreeDecryptPara.OriginatorPublicKey = publicKeyAgree.OriginatorPublicKeyInfo.PublicKey;
                        } 

                        if (!CAPI.CryptMsgControl(m_safeCryptMsgHandle,
                                                  0,
                                                  CAPI.CMSG_CTRL_KEY_AGREE_DECRYPT, 
                                                  new IntPtr(&keyAgreeDecryptPara)))
                            hr2 = Marshal.GetHRForLastWin32Error(); 
 
                        GC.KeepAlive(keyAgreeDecryptPara);
                        GC.KeepAlive(pOriginatorCert); 
                        break;

                    default:
                        throw new CryptographicException(CAPI.E_NOTIMPL); 
                    }
 
                    GC.KeepAlive(cmsgDecryptParam); 
                }
 
                // Content decrypted?
                if (hr2 == CAPI.S_OK) {
                    // Yes, so retrieve it.
                    uint cbContent = 0; 
                    SafeLocalAllocHandle pbContent = SafeLocalAllocHandle.InvalidHandle;
 
                    PkcsUtils.GetParam(m_safeCryptMsgHandle, CAPI.CMSG_CONTENT_PARAM, 0, out pbContent, out cbContent); 

                    if (cbContent > 0) { 
                        Oid contentType = PkcsUtils.GetContentType(m_safeCryptMsgHandle);
                        byte[] content = new byte[cbContent];
                        Marshal.Copy(pbContent.DangerousGetHandle(), content, 0, (int) cbContent);
 
                        m_contentInfo = new ContentInfo(contentType, content);
                    } 
 
                    pbContent.Dispose();
 
                    hr = CAPI.S_OK;
                    break;
                }
                else { 
                    // Try next recipient.
                    hr = hr2; 
                } 
            }
 
            if (hr != CAPI.S_OK)
                throw new CryptographicException(hr);

            return; 
        }
 
        private unsafe void EncryptContent (CmsRecipientCollection recipients) { 
            CMSG_ENCRYPT_PARAM encryptParam = new CMSG_ENCRYPT_PARAM();
 
            if (recipients.Count < 1)
                throw new CryptographicException(CAPI.CRYPT_E_RECIPIENT_NOT_FOUND);

            foreach (CmsRecipient recipient in recipients) { 
                if (recipient.Certificate == null)
                    throw new ArgumentNullException(SecurityResources.GetResourceString("Cryptography_Cms_RecipientCertificateNotFound")); 
 
                if ((PkcsUtils.GetRecipientInfoType(recipient.Certificate) == RecipientInfoType.KeyAgreement) ||
                    (recipient.RecipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier)) 
                    encryptParam.useCms = true;
            }

            if (!encryptParam.useCms) { 
                if (this.Certificates.Count > 0 || this.UnprotectedAttributes.Count > 0) {
                    encryptParam.useCms = true; 
                } 
            }
 
            if (encryptParam.useCms && !PkcsUtils.CmsSupported()) {
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Not_Supported"));
            }
 
            CAPI.CMSG_ENVELOPED_ENCODE_INFO encodeInfo = new CAPI.CMSG_ENVELOPED_ENCODE_INFO(Marshal.SizeOf(typeof(CAPI.CMSG_ENVELOPED_ENCODE_INFO)));
            SafeLocalAllocHandle ceei = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_ENVELOPED_ENCODE_INFO)))); 
 
            SetCspParams(this.ContentEncryptionAlgorithm, ref encryptParam);
            encodeInfo.ContentEncryptionAlgorithm.pszObjId = this.ContentEncryptionAlgorithm.Oid.Value; 
            //encodeInfo.hCryptProv = encryptParam.safeCryptProvHandle.DangerousGetHandle();
            if (encryptParam.pvEncryptionAuxInfo != null && !encryptParam.pvEncryptionAuxInfo.IsInvalid) {
                encodeInfo.pvEncryptionAuxInfo = encryptParam.pvEncryptionAuxInfo.DangerousGetHandle();
            } 

            encodeInfo.cRecipients = (uint) recipients.Count; 
 
            if (encryptParam.useCms) {
                SetCmsRecipientParams(recipients, this.Certificates, this.UnprotectedAttributes, this.ContentEncryptionAlgorithm, ref encryptParam); 
                encodeInfo.rgCmsRecipients = encryptParam.rgpRecipients.DangerousGetHandle();
                if (encryptParam.rgCertEncoded != null && !encryptParam.rgCertEncoded.IsInvalid) {
                    encodeInfo.cCertEncoded = (uint) this.Certificates.Count;
                    encodeInfo.rgCertEncoded = encryptParam.rgCertEncoded.DangerousGetHandle(); 
                }
                if (encryptParam.rgUnprotectedAttr != null && !encryptParam.rgUnprotectedAttr.IsInvalid) { 
                    encodeInfo.cUnprotectedAttr = (uint) this.UnprotectedAttributes.Count; 
                    encodeInfo.rgUnprotectedAttr = encryptParam.rgUnprotectedAttr.DangerousGetHandle();
                } 
            }
            else {
                SetPkcs7RecipientParams(recipients, ref encryptParam);
                encodeInfo.rgpRecipients = encryptParam.rgpRecipients.DangerousGetHandle(); 
            }
 
            Marshal.StructureToPtr(encodeInfo, ceei.DangerousGetHandle(), false); 

            try { 
                SafeCryptMsgHandle safeCryptMsgHandle = CAPI.CryptMsgOpenToEncode(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                                                  0,
                                                                                  CAPI.CMSG_ENVELOPED,
                                                                                  ceei.DangerousGetHandle(), 
                                                                                  this.ContentInfo.ContentType.Value,
                                                                                  IntPtr.Zero); 
                if (safeCryptMsgHandle == null || safeCryptMsgHandle.IsInvalid) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid) {
                    m_safeCryptMsgHandle.Dispose();
                }
 
                m_safeCryptMsgHandle = safeCryptMsgHandle;
            } 
            finally { 
                Marshal.DestroyStructure(ceei.DangerousGetHandle(), typeof(CAPI.CMSG_ENVELOPED_ENCODE_INFO));
                ceei.Dispose(); 
            }

            byte[] encodedContent = new byte[0];
            if (String.Compare(this.ContentInfo.ContentType.Value, CAPI.szOID_RSA_data, StringComparison.OrdinalIgnoreCase) == 0) { 
                byte[] content = this.ContentInfo.Content;
                fixed (byte * pbContent = content) { 
                    CAPI.CRYPTOAPI_BLOB dataBlob = new CAPI.CRYPTOAPI_BLOB(); 
                    dataBlob.cbData = (uint) content.Length;
                    dataBlob.pbData = new IntPtr(pbContent); 
                    if (!CAPI.EncodeObject(new IntPtr(CAPI.X509_OCTET_STRING), new IntPtr(&dataBlob), out encodedContent))
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                }
            } 
            else {
                encodedContent = this.ContentInfo.Content; 
            } 
            if (encodedContent.Length > 0) {
                if (!CAPI.CryptMsgUpdate(m_safeCryptMsgHandle, encodedContent, (uint) encodedContent.Length, true)) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            }

            // Keep alive 
            GC.KeepAlive(encryptParam);
            GC.KeepAlive(recipients); 
        } 

        // 
        // Private static methods.
        //

        private static unsafe SafeCryptMsgHandle OpenToDecode (byte[] encodedMessage) { 
            SafeCryptMsgHandle safeCryptMsgHandle = null;
 
            // Open the message for decode. 
            safeCryptMsgHandle = CAPI.CryptMsgOpenToDecode(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                           0, 
                                                           0,
                                                           IntPtr.Zero,
                                                           IntPtr.Zero,
                                                           IntPtr.Zero); 
            if (safeCryptMsgHandle == null || safeCryptMsgHandle.IsInvalid)
                throw new CryptographicException(Marshal.GetLastWin32Error()); 
 
            // ---- the message.
            if (!CAPI.CryptMsgUpdate(safeCryptMsgHandle, encodedMessage, (uint) encodedMessage.Length, true)) 
                throw new CryptographicException(Marshal.GetLastWin32Error());

            // Make sure this is EnvelopedData type.
            if (CAPI.CMSG_ENVELOPED != PkcsUtils.GetMessageType(safeCryptMsgHandle)) 
                throw new CryptographicException(CAPI.CRYPT_E_INVALID_MSG_TYPE);
 
            return safeCryptMsgHandle; 
        }
 
        private static unsafe int /* HRESULT */ GetCspParams (RecipientInfo recipientInfo,
                                                              X509Certificate2Collection extraStore,
                                                              ref CMSG_DECRYPT_PARAM cmsgDecryptParam) {
            int hr = CAPI.CRYPT_E_RECIPIENT_NOT_FOUND; 
            SafeCertContextHandle safeCertContextHandle = SafeCertContextHandle.InvalidHandle;
            SafeCertStoreHandle safeCertStoreHandle = BuildDecryptorStore(extraStore); 
 
            switch (recipientInfo.Type) {
            case RecipientInfoType.KeyTransport: 
                if (recipientInfo.SubType == RecipientSubType.Pkcs7KeyTransport) {
                    safeCertContextHandle = CAPI.CertFindCertificateInStore(safeCertStoreHandle,
                                                                            CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                                            0, 
                                                                            CAPI.CERT_FIND_SUBJECT_CERT,
                                                                            recipientInfo.pCmsgRecipientInfo.DangerousGetHandle(), 
                                                                            SafeCertContextHandle.InvalidHandle); 
                }
                else { 
                    CAPI.CMSG_KEY_TRANS_RECIPIENT_INFO keyTrans = (CAPI.CMSG_KEY_TRANS_RECIPIENT_INFO) recipientInfo.CmsgRecipientInfo;
                    safeCertContextHandle = CAPI.CertFindCertificateInStore(safeCertStoreHandle,
                                                                            CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                                            0, 
                                                                            CAPI.CERT_FIND_CERT_ID,
                                                                            new IntPtr((byte *) &keyTrans.RecipientId), 
                                                                            SafeCertContextHandle.InvalidHandle); 
                }
                break; 

            case RecipientInfoType.KeyAgreement:
                KeyAgreeRecipientInfo keyAgree = (KeyAgreeRecipientInfo) recipientInfo;
                CAPI.CERT_ID recipientId = keyAgree.RecipientId; 
                safeCertContextHandle = CAPI.CertFindCertificateInStore(safeCertStoreHandle,
                                                                        CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                                        0, 
                                                                        CAPI.CERT_FIND_CERT_ID,
                                                                        new IntPtr(&recipientId), 
                                                                        SafeCertContextHandle.InvalidHandle);
                break;

            default: // Others not supported. 
                hr = CAPI.E_NOTIMPL;
                break; 
            } 

            // Acquire CSP if the recipient's cert is found. 
            if (safeCertContextHandle != null && !safeCertContextHandle.IsInvalid) {
                SafeCryptProvHandle safeCryptProvHandle = SafeCryptProvHandle.InvalidHandle;
                uint keySpec = 0;
                bool freeCsp = false; 

                // Check to see if KEY_PROV_INFO contains "MS Base ..." 
                // If so, acquire "MS Enhanced..." or "MS Strong". 
                // if failed, then use CryptAcquireCertificatePrivateKey
                CspParameters parameters = new CspParameters(); 
                if (X509Utils.GetPrivateKeyInfo(safeCertContextHandle, ref parameters) == false)
                    throw new CryptographicException(Marshal.GetLastWin32Error());

                if (String.Compare(parameters.ProviderName, CAPI.MS_DEF_PROV, StringComparison.OrdinalIgnoreCase) == 0) { 
                    if (CAPI.CryptAcquireContext(ref safeCryptProvHandle, parameters.KeyContainerName, CAPI.MS_ENHANCED_PROV, CAPI.PROV_RSA_FULL, 0) ||
                        CAPI.CryptAcquireContext(ref safeCryptProvHandle, parameters.KeyContainerName, CAPI.MS_STRONG_PROV,   CAPI.PROV_RSA_FULL, 0)) { 
                            cmsgDecryptParam.safeCryptProvHandle = safeCryptProvHandle; 
                    }
                } 

                cmsgDecryptParam.safeCertContextHandle = safeCertContextHandle;
                cmsgDecryptParam.keySpec = (uint)parameters.KeyNumber;
                hr = CAPI.S_OK; 

                if ((safeCryptProvHandle == null) || (safeCryptProvHandle.IsInvalid)) { 
                    if (CAPI.CryptAcquireCertificatePrivateKey(safeCertContextHandle, 
                                                            CAPI.CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CAPI.CRYPT_ACQUIRE_USE_PROV_INFO_FLAG,
                                                            IntPtr.Zero, 
                                                            ref safeCryptProvHandle,
                                                            ref keySpec,
                                                            ref freeCsp)) {
                        if (!freeCsp) { 
                            GC.SuppressFinalize(safeCryptProvHandle);
                        } 
 
                        cmsgDecryptParam.safeCryptProvHandle = safeCryptProvHandle;
                    } 
                    else {
                        hr = Marshal.GetHRForLastWin32Error();
                    }
                } 
            }
 
            return hr; 
        }
 
        private static unsafe void SetCspParams (AlgorithmIdentifier contentEncryptionAlgorithm, ref CMSG_ENCRYPT_PARAM encryptParam) {

            encryptParam.safeCryptProvHandle = SafeCryptProvHandle.InvalidHandle;
            encryptParam.pvEncryptionAuxInfo = SafeLocalAllocHandle.InvalidHandle; 

            // Try with CRYPT_VERIFYCONTEXT first, and then without in case this is Win9x platform. 
            SafeCryptProvHandle hCryptProv = SafeCryptProvHandle.InvalidHandle; 
            if (!CAPI.CryptAcquireContext(ref hCryptProv, IntPtr.Zero, IntPtr.Zero, CAPI.PROV_RSA_FULL, CAPI.CRYPT_VERIFYCONTEXT) &&
                !CAPI.CryptAcquireContext(ref hCryptProv, IntPtr.Zero, IntPtr.Zero, CAPI.PROV_RSA_FULL, 0)) { 
                throw new CryptographicException(Marshal.GetLastWin32Error());
            }

            uint algId = X509Utils.OidToAlgId(contentEncryptionAlgorithm.Oid.Value); 
            if (algId == CAPI.CALG_RC2 || algId == CAPI.CALG_RC4) {
                CAPI.CMSG_RC2_AUX_INFO auxInfo = new CAPI.CMSG_RC2_AUX_INFO(Marshal.SizeOf(typeof(CAPI.CMSG_RC2_AUX_INFO))); 
                uint keyLength = (uint) contentEncryptionAlgorithm.KeyLength; 
                if (keyLength == 0) {
                    keyLength = (uint) PkcsUtils.GetMaxKeyLength(hCryptProv, algId); 
                }
                auxInfo.dwBitLen = keyLength;
                SafeLocalAllocHandle pvAuxInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_RC2_AUX_INFO))));
                Marshal.StructureToPtr(auxInfo, pvAuxInfo.DangerousGetHandle(), false); 
                encryptParam.pvEncryptionAuxInfo = pvAuxInfo;
            } 
 
            encryptParam.safeCryptProvHandle = hCryptProv;
        } 

        private static unsafe void SetCmsRecipientParams(CmsRecipientCollection           recipients,
                                                         X509Certificate2Collection      certificates,
                                                         CryptographicAttributeObjectCollection unprotectedAttributes, 
                                                         AlgorithmIdentifier              contentEncryptionAlgorithm,
                                                         ref CMSG_ENCRYPT_PARAM           encryptParam) { 
            int index = 0; 
            uint[] recipientInfoTypes = new uint[recipients.Count];
            int cKeyAgree = 0; 
            int reiSize = recipients.Count * Marshal.SizeOf(typeof(CAPI.CMSG_RECIPIENT_ENCODE_INFO));
            int totalSize = reiSize;

            for (index = 0; index < recipients.Count; index++) { 
                recipientInfoTypes[index] = (uint) PkcsUtils.GetRecipientInfoType(recipients[index].Certificate);
 
                if (recipientInfoTypes[index] == CAPI.CMSG_KEY_TRANS_RECIPIENT) { 
                    totalSize += Marshal.SizeOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO));
                } 
                else if (recipientInfoTypes[index] == CAPI.CMSG_KEY_AGREE_RECIPIENT) {
                    cKeyAgree++;
                    totalSize += Marshal.SizeOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO));
                } 
                else {
                    throw new CryptographicException(CAPI.CRYPT_E_UNKNOWN_ALGO); 
                } 
            }
 
            encryptParam.rgpRecipients = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(totalSize));
            encryptParam.rgCertEncoded = SafeLocalAllocHandle.InvalidHandle;
            encryptParam.rgUnprotectedAttr = SafeLocalAllocHandle.InvalidHandle;
            encryptParam.rgSubjectKeyIdentifier = new SafeLocalAllocHandle[recipients.Count]; 
            encryptParam.rgszObjId = new SafeLocalAllocHandle[recipients.Count];
 
            if (cKeyAgree > 0) { 
                encryptParam.rgszKeyWrapObjId = new SafeLocalAllocHandle[cKeyAgree];
                encryptParam.rgKeyWrapAuxInfo = new SafeLocalAllocHandle[cKeyAgree]; 
                encryptParam.rgEphemeralIdentifier = new SafeLocalAllocHandle[cKeyAgree];
                encryptParam.rgszEphemeralObjId = new SafeLocalAllocHandle[cKeyAgree];
                encryptParam.rgUserKeyingMaterial = new SafeLocalAllocHandle[cKeyAgree];
                encryptParam.prgpEncryptedKey = new SafeLocalAllocHandle[cKeyAgree]; 
                encryptParam.rgpEncryptedKey = new SafeLocalAllocHandle[cKeyAgree];
            } 
 
            // Create encode certs array.
            if (certificates.Count > 0) { 
                encryptParam.rgCertEncoded = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(certificates.Count * Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB))));
                for (index = 0; index < certificates.Count; index++) {
                    CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(X509Utils.GetCertContext(certificates[index]).DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT));
                    CAPI.CRYPTOAPI_BLOB * pBlob = (CAPI.CRYPTOAPI_BLOB *) new IntPtr((long) encryptParam.rgCertEncoded.DangerousGetHandle() + 
                                                                                     (index * Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB))));
                    pBlob->cbData = pCertContext.cbCertEncoded; 
                    pBlob->pbData = pCertContext.pbCertEncoded; 
                }
            } 

            // Create unprotected attributes array.
            if (unprotectedAttributes.Count > 0) {
                encryptParam.rgUnprotectedAttr = new SafeLocalAllocHandle(PkcsUtils.CreateCryptAttributes(unprotectedAttributes)); 
            }
 
            // pKeyInfo = CMSG_ENVELOPED_ENCODE_INFO.rgCmsRecipients 
            cKeyAgree = 0;
            IntPtr pKeyInfo = new IntPtr((long) encryptParam.rgpRecipients.DangerousGetHandle() + reiSize); 
            for (index = 0; index < recipients.Count; index++) {
                CmsRecipient recipient = recipients[index];
                X509Certificate2 certificate = recipient.Certificate;
                CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(X509Utils.GetCertContext(certificate).DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT)); 
                CAPI.CERT_INFO certInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
 
                CAPI.CMSG_RECIPIENT_ENCODE_INFO * pEncodeInfo = (CAPI.CMSG_RECIPIENT_ENCODE_INFO *) new IntPtr((long) encryptParam.rgpRecipients.DangerousGetHandle() + 
                                                                                                               (index * Marshal.SizeOf(typeof(CAPI.CMSG_RECIPIENT_ENCODE_INFO))));
                // CMSG_RECIPIENT_ENCODE_INFO.dwRecipientChoice 
                pEncodeInfo->dwRecipientChoice = (uint) recipientInfoTypes[index];

                // CMSG_RECIPIENT_ENCODE_INFO.pRecipientInfo (pKeyTrans or pKeyAgree)
                pEncodeInfo->pRecipientInfo = pKeyInfo; 

                if (recipientInfoTypes[index] == CAPI.CMSG_KEY_TRANS_RECIPIENT) { 
                    // Fill in CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO. 

                    // cbSize 
                    IntPtr pcbSize = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO), "cbSize"));
                    Marshal.WriteInt32(pcbSize, Marshal.SizeOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO)));

                    // KeyEncryptionAlgorithm 
                    IntPtr pKeyEncryptionAlgorithm = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO), "KeyEncryptionAlgorithm"));
 
                    byte[] objId = Encoding.ASCII.GetBytes(certInfo.SubjectPublicKeyInfo.Algorithm.pszObjId); 
                    encryptParam.rgszObjId[index] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(objId.Length + 1));
                    Marshal.Copy(objId, 0, encryptParam.rgszObjId[index].DangerousGetHandle(), objId.Length); 

                    // KeyEncryptionAlgorithm.pszObjId
                    IntPtr pszObjId = new IntPtr((long) pKeyEncryptionAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "pszObjId"));
                    Marshal.WriteIntPtr(pszObjId, encryptParam.rgszObjId[index].DangerousGetHandle()); 

                    // KeyEncryptionAlgorithm.Parameters 
                    IntPtr pParameters = new IntPtr((long) pKeyEncryptionAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "Parameters")); 

                    // KeyEncryptionAlgorithm.Parameters.cbData 
                    IntPtr pcbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
                    Marshal.WriteInt32(pcbData, (int) certInfo.SubjectPublicKeyInfo.Algorithm.Parameters.cbData);

                    // KeyEncryptionAlgorithm.Parameters.pbData 
                    IntPtr ppbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData"));
                    Marshal.WriteIntPtr(ppbData, certInfo.SubjectPublicKeyInfo.Algorithm.Parameters.pbData); 
 
                    // Skip pvKeyEncryptionAuxInfo
                    // Skip hCryptProv 

                    // RecipientPublicKey
                    IntPtr pRecipientPublicKey = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO), "RecipientPublicKey"));
 
                    // RecipientPublicKey.cbData
                    pcbData = new IntPtr((long) pRecipientPublicKey + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_BIT_BLOB), "cbData")); 
                    Marshal.WriteInt32(pcbData, (int) certInfo.SubjectPublicKeyInfo.PublicKey.cbData); 

                    // RecipientPublicKey.pbData 
                    ppbData = new IntPtr((long) pRecipientPublicKey + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_BIT_BLOB), "pbData"));
                    Marshal.WriteIntPtr(ppbData, certInfo.SubjectPublicKeyInfo.PublicKey.pbData);

                    // RecipientPublicKey.cUnusedBits 
                    IntPtr pcUnusedBIts = new IntPtr((long) pRecipientPublicKey + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_BIT_BLOB), "cUnusedBits"));
                    Marshal.WriteInt32(pcUnusedBIts, (int) certInfo.SubjectPublicKeyInfo.PublicKey.cUnusedBits); 
 
                    // RecipientId
                    IntPtr pRecipientId = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO), "RecipientId")); 
                    if (recipient.RecipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier) {
                        uint cbData = 0;
                        SafeLocalAllocHandle pbData = SafeLocalAllocHandle.InvalidHandle;
                        if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate), 
                                                                    CAPI.CERT_KEY_IDENTIFIER_PROP_ID,
                                                                    pbData, 
                                                                    ref cbData)) 
                            throw new CryptographicException(Marshal.GetLastWin32Error());
 
                        pbData = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbData));

                        if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate),
                                                                    CAPI.CERT_KEY_IDENTIFIER_PROP_ID, 
                                                                    pbData,
                                                                    ref cbData)) 
                            throw new CryptographicException(Marshal.GetLastWin32Error()); 

                        encryptParam.rgSubjectKeyIdentifier[index] = pbData; 

                        // RecipientId.dwIdChoice
                        IntPtr pdwIdChoice = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "dwIdChoice"));
                        Marshal.WriteInt32(pdwIdChoice, (int) CAPI.CERT_ID_KEY_IDENTIFIER); 

                        // RecipientId.KeyId 
                        IntPtr pKeyId = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "Value")); 

                        // RecipientId.KeyId.cbData 
                        pcbData = new IntPtr((long) pKeyId + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
                        Marshal.WriteInt32(pcbData, (int) cbData);

                        // RecipientId.KeyId.pbData 
                        ppbData = new IntPtr((long) pKeyId + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData"));
                        Marshal.WriteIntPtr(ppbData, pbData.DangerousGetHandle()); 
                    } 
                    else {
                        // RecipientId.dwIdChoice 
                        IntPtr pdwIdChoice = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "dwIdChoice"));
                        Marshal.WriteInt32(pdwIdChoice, (int) CAPI.CERT_ID_ISSUER_SERIAL_NUMBER);

                        // RecipientId.IssuerSerialNumber 
                        IntPtr pIssuerSerialNumber = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "Value"));
 
                        // RecipientId.IssuerSerialNumber.Issuer 
                        IntPtr pIssuer = new IntPtr((long) pIssuerSerialNumber + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ISSUER_SERIAL_NUMBER), "Issuer"));
 
                        // RecipientId.IssuerSerialNumber.Issuer.cbData
                        pcbData = new IntPtr((long) pIssuer + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
                        Marshal.WriteInt32(pcbData, (int) certInfo.Issuer.cbData);
 
                        // RecipientId.IssuerSerialNumber.Issuer.pbData
                        ppbData = new IntPtr((long) pIssuer + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData")); 
                        Marshal.WriteIntPtr(ppbData, certInfo.Issuer.pbData); 

                        // RecipientId.IssuerSerialNumber.SerialNumber 
                        IntPtr pSerialNumber = new IntPtr((long) pIssuerSerialNumber + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ISSUER_SERIAL_NUMBER), "SerialNumber"));

                        // RecipientId.IssuerSerialNumber.SerialNumber.cbData
                        pcbData = new IntPtr((long) pSerialNumber + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData")); 
                        Marshal.WriteInt32(pcbData, (int) certInfo.SerialNumber.cbData);
 
                        // RecipientId.IssuerSerialNumber.SerialNumber.pbData 
                        ppbData = new IntPtr((long) pSerialNumber + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData"));
                        Marshal.WriteIntPtr(ppbData, certInfo.SerialNumber.pbData); 
                    }
                    pKeyInfo = new IntPtr((long) pKeyInfo + Marshal.SizeOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO)));
                }
                else if (recipientInfoTypes[index] == CAPI.CMSG_KEY_AGREE_RECIPIENT) { 
                    // Fill in CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO.
 
                    // cbSize 
                    IntPtr pcbSize = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "cbSize"));
                    Marshal.WriteInt32(pcbSize, Marshal.SizeOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO))); 

                    // KeyEncryptionAlgorithm
                    IntPtr pKeyEncryptionAlgorithm = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "KeyEncryptionAlgorithm"));
 
                    byte[] objId = Encoding.ASCII.GetBytes(CAPI.szOID_RSA_SMIMEalgESDH);
                    encryptParam.rgszObjId[index] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(objId.Length + 1)); 
                    Marshal.Copy(objId, 0, encryptParam.rgszObjId[index].DangerousGetHandle(), objId.Length); 

                    // KeyEncryptionAlgorithm.pszObjId 
                    IntPtr pszObjId = new IntPtr((long) pKeyEncryptionAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "pszObjId"));
                    Marshal.WriteIntPtr(pszObjId, encryptParam.rgszObjId[index].DangerousGetHandle());

                    // Skip KeyEncryptionAlgorithm.Parameters 
                    // Skip pvKeyEncryptionAuxInfo
 
                    // KeyWrapAlgorithm 
                    IntPtr pKeyWrapAlgorithm = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "KeyWrapAlgorithm"));
 
                    uint algId = X509Utils.OidToAlgId(contentEncryptionAlgorithm.Oid.Value);
                    if (algId == CAPI.CALG_RC2) {
                        objId = Encoding.ASCII.GetBytes(CAPI.szOID_RSA_SMIMEalgCMSRC2wrap);
                    } 
                    else {
                        objId = Encoding.ASCII.GetBytes(CAPI.szOID_RSA_SMIMEalgCMS3DESwrap); 
                    } 
                    encryptParam.rgszKeyWrapObjId[cKeyAgree] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(objId.Length + 1));
                    Marshal.Copy(objId, 0, encryptParam.rgszKeyWrapObjId[cKeyAgree].DangerousGetHandle(), objId.Length); 

                    // KeyWrapAlgorithm.pszObjId
                    pszObjId = new IntPtr((long) pKeyWrapAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "pszObjId"));
                    Marshal.WriteIntPtr(pszObjId, encryptParam.rgszKeyWrapObjId[cKeyAgree].DangerousGetHandle()); 

                    // Skip KeyWrapAlgorithm.Parameters 
 
                    // Fill in pvKeyWrapAuxInfo for RC2.
                    if (algId == CAPI.CALG_RC2) { 
                        IntPtr pKeyWrapAuxInfo = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "pvKeyWrapAuxInfo"));
                        Marshal.WriteIntPtr(pKeyWrapAuxInfo, encryptParam.pvEncryptionAuxInfo.DangerousGetHandle());
                    }
 
                    // Skip hCryptProv
                    // Skip dwKeySpec 
 
                    // dwKeyChoice
                    IntPtr pdwKeyChoice = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "dwKeyChoice")); 
                    Marshal.WriteInt32(pdwKeyChoice, (int) CAPI.CMSG_KEY_AGREE_EPHEMERAL_KEY_CHOICE);

                    // pEphemeralAlgorithm
                    IntPtr pEphemeralAlgorithm = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "pEphemeralAlgorithmOrSenderId")); 
                    encryptParam.rgEphemeralIdentifier[cKeyAgree] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER))));
                    Marshal.WriteIntPtr(pEphemeralAlgorithm, encryptParam.rgEphemeralIdentifier[cKeyAgree].DangerousGetHandle()); 
 
                    // pEphemeralAlgorithm.pszObjId
                    objId = Encoding.ASCII.GetBytes(certInfo.SubjectPublicKeyInfo.Algorithm.pszObjId); 
                    encryptParam.rgszEphemeralObjId[cKeyAgree] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(objId.Length + 1));
                    Marshal.Copy(objId, 0, encryptParam.rgszEphemeralObjId[cKeyAgree].DangerousGetHandle(), objId.Length);

                    pszObjId = new IntPtr((long) encryptParam.rgEphemeralIdentifier[cKeyAgree].DangerousGetHandle() + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "pszObjId")); 
                    Marshal.WriteIntPtr(pszObjId, encryptParam.rgszEphemeralObjId[cKeyAgree].DangerousGetHandle());
 
                    // pEphemeralAlgorithm.Parameters 
                    IntPtr pParameters = new IntPtr((long) encryptParam.rgEphemeralIdentifier[cKeyAgree].DangerousGetHandle() + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "Parameters"));
 
                    // pEphemeralAlgorithm.Parameters.cbData
                    IntPtr pcbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
                    Marshal.WriteInt32(pcbData, (int) certInfo.SubjectPublicKeyInfo.Algorithm.Parameters.cbData);
 
                    // pEphemeralAlgorithm.Parameters.pbData
                    IntPtr ppbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData")); 
                    Marshal.WriteIntPtr(ppbData, certInfo.SubjectPublicKeyInfo.Algorithm.Parameters.pbData); 

                    // Skip UserKeyingMaterial 

                    // cRecipientEncryptedKeys
                    IntPtr pcRecipientEncryptedKeys = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "cRecipientEncryptedKeys"));
                    Marshal.WriteInt32(pcRecipientEncryptedKeys, 1); 

                    // rgpRecipientEncryptedKeys 
                    encryptParam.prgpEncryptedKey[cKeyAgree] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(IntPtr)))); 
                    IntPtr prgpRecipientEncryptedKeys = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "rgpRecipientEncryptedKeys"));
                    Marshal.WriteIntPtr(prgpRecipientEncryptedKeys, encryptParam.prgpEncryptedKey[cKeyAgree].DangerousGetHandle()); 
                    encryptParam.rgpEncryptedKey[cKeyAgree] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO))));
                    Marshal.WriteIntPtr(encryptParam.prgpEncryptedKey[cKeyAgree].DangerousGetHandle(), encryptParam.rgpEncryptedKey[cKeyAgree].DangerousGetHandle());

                    // rgpRecipientEncryptedKeys.cbSize 
                    pcbSize = new IntPtr((long) encryptParam.rgpEncryptedKey[cKeyAgree].DangerousGetHandle() + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO), "cbSize"));
                    Marshal.WriteInt32(pcbSize, Marshal.SizeOf(typeof(CAPI.CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO))); 
 
                    // rgpRecipientEncryptedKeys.RecipientPublicKey
                    IntPtr pRecipientPublicKey = new IntPtr((long) encryptParam.rgpEncryptedKey[cKeyAgree].DangerousGetHandle() + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO), "RecipientPublicKey")); 

                    // rgpRecipientEncryptedKeys.RecipientPublicKey.cbData
                    pcbData = new IntPtr((long) pRecipientPublicKey + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_BIT_BLOB), "cbData"));
                    Marshal.WriteInt32(pcbData, (int) certInfo.SubjectPublicKeyInfo.PublicKey.cbData); 

                    // rgpRecipientEncryptedKeys.RecipientPublicKey.pbData 
                    ppbData = new IntPtr((long) pRecipientPublicKey + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_BIT_BLOB), "pbData")); 
                    Marshal.WriteIntPtr(ppbData, certInfo.SubjectPublicKeyInfo.PublicKey.pbData);
 
                    // rgpRecipientEncryptedKeys.RecipientPublicKey.cUnusedBits
                    IntPtr pcUnusedBits = new IntPtr((long) pRecipientPublicKey + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_BIT_BLOB), "cUnusedBits"));
                    Marshal.WriteInt32(pcUnusedBits, (int) certInfo.SubjectPublicKeyInfo.PublicKey.cUnusedBits);
 
                    // rgpRecipientEncryptedKeys.RecipientId
                    IntPtr pRecipientId = new IntPtr((long) encryptParam.rgpEncryptedKey[cKeyAgree].DangerousGetHandle() + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO), "RecipientId")); 
 
                    // rgpRecipientEncryptedKeys.RecipientId.dwIdChoice
                    IntPtr pdwIdChoice = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "dwIdChoice")); 

                    if (recipient.RecipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier) {
                        Marshal.WriteInt32(pdwIdChoice, (int) CAPI.CERT_ID_KEY_IDENTIFIER);
 
                        // rgpRecipientEncryptedKeys.RecipientId.KeyId
                        IntPtr pKeyId = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "Value")); 
 
                        uint cbKeyId = 0;
                        SafeLocalAllocHandle pbKeyId = SafeLocalAllocHandle.InvalidHandle; 
                        if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate),
                                                                    CAPI.CERT_KEY_IDENTIFIER_PROP_ID,
                                                                    pbKeyId,
                                                                    ref cbKeyId)) 
                            throw new CryptographicException(Marshal.GetLastWin32Error());
 
                        pbKeyId = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbKeyId)); 
                        if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate),
                                                                    CAPI.CERT_KEY_IDENTIFIER_PROP_ID, 
                                                                    pbKeyId,
                                                                    ref cbKeyId))
                            throw new CryptographicException(Marshal.GetLastWin32Error());
 
                        encryptParam.rgSubjectKeyIdentifier[cKeyAgree] = pbKeyId;
 
                        // rgpRecipientEncryptedKeys.RecipientId.KeyId.cbData 
                        pcbData = new IntPtr((long) pKeyId + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
                        Marshal.WriteInt32(pcbData, (int) cbKeyId); 

                        // rgpRecipientEncryptedKeys.RecipientId.KeyId.pbData
                        ppbData = new IntPtr((long) pKeyId + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData"));
                        Marshal.WriteIntPtr(ppbData, pbKeyId.DangerousGetHandle()); 
                    }
                    else { 
                        Marshal.WriteInt32(pdwIdChoice, (int) CAPI.CERT_ID_ISSUER_SERIAL_NUMBER); 

                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber 
                        IntPtr pIssuerSerial = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "Value"));

                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber.Issuer
                        IntPtr pIssuer = new IntPtr((long) pIssuerSerial + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ISSUER_SERIAL_NUMBER), "Issuer")); 

                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber.Issuer.cbData 
                        pcbData = new IntPtr((long) pIssuer + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData")); 
                        Marshal.WriteInt32(pcbData, (int) certInfo.Issuer.cbData);
 
                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber.Issuer.pbData
                        ppbData = new IntPtr((long) pIssuer + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData"));
                        Marshal.WriteIntPtr(ppbData, certInfo.Issuer.pbData);
 
                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber.SerialNumber
                        IntPtr pSerialNumber = new IntPtr((long) pIssuerSerial + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ISSUER_SERIAL_NUMBER), "SerialNumber")); 
 
                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber.SerialNumber.cbData
                        pcbData = new IntPtr((long) pSerialNumber + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData")); 
                        Marshal.WriteInt32(pcbData, (int) certInfo.SerialNumber.cbData);

                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber.SerialNumber.pbData
                        ppbData = new IntPtr((long) pSerialNumber + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData")); 
                        Marshal.WriteIntPtr(ppbData, certInfo.SerialNumber.pbData);
                    } 
 
                    // Bump key agree count.
                    cKeyAgree++; 
                    pKeyInfo = new IntPtr((long) pKeyInfo + Marshal.SizeOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO)));
                }
                else {
                    // Should never get here! 
                    Debug.Assert(false);
                } 
            } 
        }
 
        private static unsafe void SetPkcs7RecipientParams (CmsRecipientCollection recipients,
                                                            ref CMSG_ENCRYPT_PARAM encryptParam) {
            int index = 0;
            uint totalSize = (uint) recipients.Count * (uint) Marshal.SizeOf(typeof(IntPtr)); 

            encryptParam.rgpRecipients = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(totalSize)); 
 
            IntPtr pCertInfo = encryptParam.rgpRecipients.DangerousGetHandle();
 
            for (index = 0; index < recipients.Count; index++) {
                CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(X509Utils.GetCertContext(recipients[index].Certificate).DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT));

                Marshal.WriteIntPtr(pCertInfo, pCertContext.pCertInfo); 
                pCertInfo = new IntPtr((long) pCertInfo + Marshal.SizeOf(typeof(IntPtr)));
            } 
        } 

        private static unsafe SafeCertStoreHandle BuildDecryptorStore (X509Certificate2Collection extraStore) { 
            // Build store where to find recipient's certificate.
            X509Certificate2Collection recipientStore = new X509Certificate2Collection();

            // Include CU and LM MY stores. 
            try {
                X509Store cuMy = new X509Store("MY", StoreLocation.CurrentUser); 
                cuMy.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly | OpenFlags.IncludeArchived); 
                recipientStore.AddRange(cuMy.Certificates);
 
            }
            catch (SecurityException) {
                // X509Store.Open() may not have permission. Ignore.
            } 
            try {
                X509Store lmMy = new X509Store("MY", StoreLocation.LocalMachine); 
                lmMy.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly | OpenFlags.IncludeArchived); 
                recipientStore.AddRange(lmMy.Certificates);
            } 
            catch (SecurityException) {
                // Ignore. May be in extra store.
            }
 
            // Finally, include extra store, if specified.
            if (extraStore != null) { 
                recipientStore.AddRange(extraStore); 
            }
 
            if (recipientStore.Count == 0)
                throw new CryptographicException(CAPI.CRYPT_E_RECIPIENT_NOT_FOUND);

            // Return memory store handle. 
            return X509Utils.ExportToMemoryStore(recipientStore);
        } 
 
        private static unsafe SafeCertStoreHandle BuildOriginatorStore (X509Certificate2Collection bagOfCerts, X509Certificate2Collection extraStore) {
            // Build store where to find originator's certificate. 
            X509Certificate2Collection originatorStore = new X509Certificate2Collection();

            // Include CU and LM MY stores.
            try { 
                X509Store cuMy = new X509Store("AddressBook", StoreLocation.CurrentUser);
                cuMy.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly | OpenFlags.IncludeArchived); 
                originatorStore.AddRange(cuMy.Certificates); 

            } 
            catch (SecurityException) {
                // X509Store.Open() may not have permission. Ignore.
            }
            try { 
                X509Store lmMy = new X509Store("AddressBook", StoreLocation.LocalMachine);
                lmMy.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly | OpenFlags.IncludeArchived); 
                originatorStore.AddRange(lmMy.Certificates); 
            }
            catch (SecurityException) { 
                // Ignore. May be in bag of certs or extra store.
            }

            // Finally, include bag of certs and extra store, if specified. 
            if (bagOfCerts != null) {
                originatorStore.AddRange(bagOfCerts); 
            } 
            if (extraStore != null) {
                originatorStore.AddRange(extraStore); 
            }

            if (originatorStore.Count == 0)
                throw new CryptographicException(CAPI.CRYPT_E_NOT_FOUND); 

            // Return memory store handle. 
            return X509Utils.ExportToMemoryStore(originatorStore); 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 

// 
// EnvelopedPkcs7.cs 
//
 
namespace System.Security.Cryptography.Pkcs {
    using System.Collections;
    using System.Diagnostics;
    using System.Globalization; 
    using System.IO;
    using System.Runtime.InteropServices; 
    using System.Security.Cryptography; 
    using System.Security.Cryptography.X509Certificates;
    using System.Security.Cryptography.Xml; 
    using System.Security.Permissions;
    using System.Text;

    [System.Security.Permissions.HostProtection(MayLeakOnAbort = true)] 
    public sealed class EnvelopedCms {
        private SafeCryptMsgHandle               m_safeCryptMsgHandle; 
        private int                              m_version; 
        private SubjectIdentifierType            m_recipientIdentifierType;
        private ContentInfo                      m_contentInfo; 
        private AlgorithmIdentifier              m_encryptionAlgorithm;
        private X509Certificate2Collection       m_certificates;
        private CryptographicAttributeObjectCollection m_unprotectedAttributes;
 
        private struct CMSG_DECRYPT_PARAM {
            internal SafeCertContextHandle  safeCertContextHandle; 
            internal SafeCryptProvHandle    safeCryptProvHandle; 
            internal uint                   keySpec;
        } 

        private struct CMSG_ENCRYPT_PARAM {
            internal bool                            useCms;
            internal SafeCryptProvHandle             safeCryptProvHandle; 
            internal SafeLocalAllocHandle            pvEncryptionAuxInfo;
            internal SafeLocalAllocHandle            rgpRecipients; 
            internal SafeLocalAllocHandle            rgCertEncoded; 
            internal SafeLocalAllocHandle            rgUnprotectedAttr;
            internal SafeLocalAllocHandle[]          rgSubjectKeyIdentifier; 
            internal SafeLocalAllocHandle[]          rgszObjId;
            internal SafeLocalAllocHandle[]          rgszKeyWrapObjId;
            internal SafeLocalAllocHandle[]          rgKeyWrapAuxInfo;
            internal SafeLocalAllocHandle[]          rgEphemeralIdentifier; 
            internal SafeLocalAllocHandle[]          rgszEphemeralObjId;
            internal SafeLocalAllocHandle[]          rgUserKeyingMaterial; 
            internal SafeLocalAllocHandle[]          prgpEncryptedKey; 
            internal SafeLocalAllocHandle[]          rgpEncryptedKey;
        } 

        //
        // Constructors.
        // 

        public EnvelopedCms () : 
            this(SubjectIdentifierType.IssuerAndSerialNumber, new ContentInfo(CAPI.szOID_RSA_data, new byte[0]), new AlgorithmIdentifier(CAPI.szOID_RSA_DES_EDE3_CBC)) { 
        }
 
        public EnvelopedCms (ContentInfo contentInfo) :
            this(SubjectIdentifierType.IssuerAndSerialNumber, contentInfo, new AlgorithmIdentifier(CAPI.szOID_RSA_DES_EDE3_CBC)) {
        }
 
        public EnvelopedCms (SubjectIdentifierType recipientIdentifierType, ContentInfo contentInfo) :
            this(recipientIdentifierType, contentInfo, new AlgorithmIdentifier(CAPI.szOID_RSA_DES_EDE3_CBC)) { 
        } 

        public EnvelopedCms (ContentInfo contentInfo, AlgorithmIdentifier encryptionAlgorithm) : 
            this(SubjectIdentifierType.IssuerAndSerialNumber, contentInfo, encryptionAlgorithm) {
        }

        public EnvelopedCms (SubjectIdentifierType recipientIdentifierType, ContentInfo contentInfo, AlgorithmIdentifier encryptionAlgorithm) { 
            if (contentInfo == null)
                throw new ArgumentNullException("contentInfo"); 
            if (contentInfo.Content == null) 
                throw new ArgumentNullException("contentInfo.Content");
            if (encryptionAlgorithm == null) 
                throw new ArgumentNullException("encryptionAlgorithm");

            m_safeCryptMsgHandle = SafeCryptMsgHandle.InvalidHandle;
            m_version = recipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier ? 2 : 0; 
            m_recipientIdentifierType = recipientIdentifierType;
            m_contentInfo = contentInfo; 
            m_encryptionAlgorithm = encryptionAlgorithm; 
            m_encryptionAlgorithm.Parameters = new byte[0];
            m_certificates = new X509Certificate2Collection(); 
            m_unprotectedAttributes = new CryptographicAttributeObjectCollection();
        }

        // 
        // Public APIs.
        // 
 
        public int Version {
            get { 
                return m_version;
            }
        }
 
        public ContentInfo ContentInfo {
            get { 
                return m_contentInfo; 
            }
        } 

        public AlgorithmIdentifier ContentEncryptionAlgorithm {
            get {
                return m_encryptionAlgorithm; 
            }
        } 
 
        public X509Certificate2Collection Certificates {
            get { 
                return m_certificates;
            }
        }
 
        public CryptographicAttributeObjectCollection UnprotectedAttributes {
            get { 
                return m_unprotectedAttributes; 
            }
        } 

        public RecipientInfoCollection RecipientInfos {
            get {
                if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid) { 
                    return new RecipientInfoCollection();
                } 
                return new RecipientInfoCollection(m_safeCryptMsgHandle); 
            }
        } 

        public byte[] Encode () {
            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid)
                throw new InvalidOperationException(SecurityResources.GetResourceString("Cryptography_Cms_MessageNotEncrypted")); 

            return PkcsUtils.GetContent(m_safeCryptMsgHandle); 
        } 

        public void Decode (byte[] encodedMessage) { 
            if (encodedMessage == null)
                throw new ArgumentNullException("encodedMessage");

            if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid) { 
                m_safeCryptMsgHandle.Dispose();
            } 
 
            // Open to decode.
            m_safeCryptMsgHandle = OpenToDecode(encodedMessage); 

            // Get version.
            m_version = (int) PkcsUtils.GetVersion(m_safeCryptMsgHandle);
 
            // Get contentInfo (content still encrypted).
            Oid contentType = PkcsUtils.GetContentType(m_safeCryptMsgHandle); 
            byte[] content = PkcsUtils.GetContent(m_safeCryptMsgHandle); 
            m_contentInfo = new ContentInfo(contentType, content);
 
            // Get encryption algorithm.
            m_encryptionAlgorithm = PkcsUtils.GetAlgorithmIdentifier(m_safeCryptMsgHandle);

            // Get certificates. 
            m_certificates = PkcsUtils.GetCertificates(m_safeCryptMsgHandle);
 
            // Get unprotected attributes. 
            m_unprotectedAttributes = PkcsUtils.GetUnprotectedAttributes(m_safeCryptMsgHandle);
        } 

        public void Encrypt () {
            Encrypt(new CmsRecipientCollection());
        } 

        public void Encrypt (CmsRecipient recipient) { 
            if (recipient == null) 
                throw new ArgumentNullException("recipient");
 
            Encrypt(new CmsRecipientCollection(recipient));
        }

        public void Encrypt (CmsRecipientCollection recipients) { 
            if (recipients == null)
                throw new ArgumentNullException("recipients"); 
 
            if (ContentInfo.Content.Length == 0)
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Envelope_Empty_Content")); 

            if (recipients.Count == 0)
                recipients = PkcsUtils.SelectRecipients(m_recipientIdentifierType);
 
            EncryptContent(recipients);
        } 
 
        public void Decrypt () {
            DecryptContent(this.RecipientInfos, null); 
        }

        public void Decrypt (RecipientInfo recipientInfo) {
            if (recipientInfo == null) 
                throw new ArgumentNullException("recipientInfo");
 
            DecryptContent(new RecipientInfoCollection(recipientInfo), null); 
        }
 
        public void Decrypt (X509Certificate2Collection extraStore) {
            if (extraStore == null)
                throw new ArgumentNullException("extraStore");
 
            DecryptContent(this.RecipientInfos, extraStore);
        } 
 
        public void Decrypt (RecipientInfo recipientInfo, X509Certificate2Collection extraStore) {
            if (recipientInfo == null) 
                throw new ArgumentNullException("recipientInfo");

            if (extraStore == null)
                throw new ArgumentNullException("extraStore"); 

            DecryptContent(new RecipientInfoCollection(recipientInfo), extraStore); 
        } 

        // 
        // Private methods.
        //

        private unsafe void DecryptContent (RecipientInfoCollection recipientInfos, X509Certificate2Collection extraStore) { 
            int hr = CAPI.CRYPT_E_RECIPIENT_NOT_FOUND;
 
            if (m_safeCryptMsgHandle == null || m_safeCryptMsgHandle.IsInvalid) 
                throw new InvalidOperationException(SecurityResources.GetResourceString("Cryptography_Cms_NoEncryptedMessageToEncode"));
 
            for (int index = 0; index < recipientInfos.Count; index++) {
                RecipientInfo recipientInfo = recipientInfos[index];
                CMSG_DECRYPT_PARAM cmsgDecryptParam = new CMSG_DECRYPT_PARAM();
 
                // Get CSP parameters
                int hr2 = GetCspParams(recipientInfo, extraStore, ref cmsgDecryptParam); 
 
                if (hr2 == CAPI.S_OK) {
                    // 


                    CspParameters parameters = new CspParameters();
                    if (X509Utils.GetPrivateKeyInfo(cmsgDecryptParam.safeCertContextHandle, ref parameters) == false) 
                        throw new CryptographicException(Marshal.GetLastWin32Error());
 
                    KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags); 
                    KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(parameters, KeyContainerPermissionFlags.Open | KeyContainerPermissionFlags.Decrypt);
                    kp.AccessEntries.Add(entry); 
                    kp.Demand();

                    // Decrypt the content.
                    switch (recipientInfo.Type) { 
                    case RecipientInfoType.KeyTransport:
                        CAPI.CMSG_CTRL_DECRYPT_PARA ctrlDecryptPara = new CAPI.CMSG_CTRL_DECRYPT_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_DECRYPT_PARA))); 
                        ctrlDecryptPara.hCryptProv = cmsgDecryptParam.safeCryptProvHandle.DangerousGetHandle(); 
                        ctrlDecryptPara.dwKeySpec = cmsgDecryptParam.keySpec;
                        ctrlDecryptPara.dwRecipientIndex = (uint) recipientInfo.Index; 

                        if (!CAPI.CryptMsgControl(m_safeCryptMsgHandle,
                                                  0,
                                                  CAPI.CMSG_CTRL_DECRYPT, 
                                                  new IntPtr(&ctrlDecryptPara)))
                            hr2 = Marshal.GetHRForLastWin32Error(); 
 
                        GC.KeepAlive(ctrlDecryptPara);
                        break; 

                    case RecipientInfoType.KeyAgreement:
                        SafeCertContextHandle pOriginatorCert = SafeCertContextHandle.InvalidHandle;
                        KeyAgreeRecipientInfo keyAgree = (KeyAgreeRecipientInfo) recipientInfo; 
                        CAPI.CMSG_CMS_RECIPIENT_INFO cmsRecipientInfo = (CAPI.CMSG_CMS_RECIPIENT_INFO) Marshal.PtrToStructure(keyAgree.pCmsgRecipientInfo.DangerousGetHandle(), typeof(CAPI.CMSG_CMS_RECIPIENT_INFO));
 
                        CAPI.CMSG_CTRL_KEY_AGREE_DECRYPT_PARA keyAgreeDecryptPara = new CAPI.CMSG_CTRL_KEY_AGREE_DECRYPT_PARA(Marshal.SizeOf(typeof(CAPI.CMSG_CTRL_KEY_AGREE_DECRYPT_PARA))); 
                        keyAgreeDecryptPara.hCryptProv = cmsgDecryptParam.safeCryptProvHandle.DangerousGetHandle();
                        keyAgreeDecryptPara.dwKeySpec = cmsgDecryptParam.keySpec; 
                        keyAgreeDecryptPara.pKeyAgree = cmsRecipientInfo.pRecipientInfo;
                        keyAgreeDecryptPara.dwRecipientIndex = keyAgree.Index;
                        keyAgreeDecryptPara.dwRecipientEncryptedKeyIndex = keyAgree.SubIndex;
 
                        if (keyAgree.SubType == RecipientSubType.CertIdKeyAgreement) {
                            CAPI.CMSG_KEY_AGREE_CERT_ID_RECIPIENT_INFO certIdKeyAgree = (CAPI.CMSG_KEY_AGREE_CERT_ID_RECIPIENT_INFO) keyAgree.CmsgRecipientInfo; 
                            SafeCertStoreHandle hCertStore = BuildOriginatorStore(this.Certificates, extraStore); 

                            pOriginatorCert = CAPI.CertFindCertificateInStore(hCertStore, 
                                                                              CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                                              0,
                                                                              CAPI.CERT_FIND_CERT_ID,
                                                                              new IntPtr(&certIdKeyAgree.OriginatorCertId), 
                                                                              SafeCertContextHandle.InvalidHandle);
                            if (pOriginatorCert == null || pOriginatorCert.IsInvalid) { 
                                hr2 = CAPI.CRYPT_E_NOT_FOUND; 
                                break;
                            } 

                            CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(pOriginatorCert.DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT));
                            CAPI.CERT_INFO certInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
                            keyAgreeDecryptPara.OriginatorPublicKey = certInfo.SubjectPublicKeyInfo.PublicKey; 
                        }
                        else { 
                            CAPI.CMSG_KEY_AGREE_PUBLIC_KEY_RECIPIENT_INFO publicKeyAgree = (CAPI.CMSG_KEY_AGREE_PUBLIC_KEY_RECIPIENT_INFO) keyAgree.CmsgRecipientInfo; 
                            keyAgreeDecryptPara.OriginatorPublicKey = publicKeyAgree.OriginatorPublicKeyInfo.PublicKey;
                        } 

                        if (!CAPI.CryptMsgControl(m_safeCryptMsgHandle,
                                                  0,
                                                  CAPI.CMSG_CTRL_KEY_AGREE_DECRYPT, 
                                                  new IntPtr(&keyAgreeDecryptPara)))
                            hr2 = Marshal.GetHRForLastWin32Error(); 
 
                        GC.KeepAlive(keyAgreeDecryptPara);
                        GC.KeepAlive(pOriginatorCert); 
                        break;

                    default:
                        throw new CryptographicException(CAPI.E_NOTIMPL); 
                    }
 
                    GC.KeepAlive(cmsgDecryptParam); 
                }
 
                // Content decrypted?
                if (hr2 == CAPI.S_OK) {
                    // Yes, so retrieve it.
                    uint cbContent = 0; 
                    SafeLocalAllocHandle pbContent = SafeLocalAllocHandle.InvalidHandle;
 
                    PkcsUtils.GetParam(m_safeCryptMsgHandle, CAPI.CMSG_CONTENT_PARAM, 0, out pbContent, out cbContent); 

                    if (cbContent > 0) { 
                        Oid contentType = PkcsUtils.GetContentType(m_safeCryptMsgHandle);
                        byte[] content = new byte[cbContent];
                        Marshal.Copy(pbContent.DangerousGetHandle(), content, 0, (int) cbContent);
 
                        m_contentInfo = new ContentInfo(contentType, content);
                    } 
 
                    pbContent.Dispose();
 
                    hr = CAPI.S_OK;
                    break;
                }
                else { 
                    // Try next recipient.
                    hr = hr2; 
                } 
            }
 
            if (hr != CAPI.S_OK)
                throw new CryptographicException(hr);

            return; 
        }
 
        private unsafe void EncryptContent (CmsRecipientCollection recipients) { 
            CMSG_ENCRYPT_PARAM encryptParam = new CMSG_ENCRYPT_PARAM();
 
            if (recipients.Count < 1)
                throw new CryptographicException(CAPI.CRYPT_E_RECIPIENT_NOT_FOUND);

            foreach (CmsRecipient recipient in recipients) { 
                if (recipient.Certificate == null)
                    throw new ArgumentNullException(SecurityResources.GetResourceString("Cryptography_Cms_RecipientCertificateNotFound")); 
 
                if ((PkcsUtils.GetRecipientInfoType(recipient.Certificate) == RecipientInfoType.KeyAgreement) ||
                    (recipient.RecipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier)) 
                    encryptParam.useCms = true;
            }

            if (!encryptParam.useCms) { 
                if (this.Certificates.Count > 0 || this.UnprotectedAttributes.Count > 0) {
                    encryptParam.useCms = true; 
                } 
            }
 
            if (encryptParam.useCms && !PkcsUtils.CmsSupported()) {
                throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Cms_Not_Supported"));
            }
 
            CAPI.CMSG_ENVELOPED_ENCODE_INFO encodeInfo = new CAPI.CMSG_ENVELOPED_ENCODE_INFO(Marshal.SizeOf(typeof(CAPI.CMSG_ENVELOPED_ENCODE_INFO)));
            SafeLocalAllocHandle ceei = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_ENVELOPED_ENCODE_INFO)))); 
 
            SetCspParams(this.ContentEncryptionAlgorithm, ref encryptParam);
            encodeInfo.ContentEncryptionAlgorithm.pszObjId = this.ContentEncryptionAlgorithm.Oid.Value; 
            //encodeInfo.hCryptProv = encryptParam.safeCryptProvHandle.DangerousGetHandle();
            if (encryptParam.pvEncryptionAuxInfo != null && !encryptParam.pvEncryptionAuxInfo.IsInvalid) {
                encodeInfo.pvEncryptionAuxInfo = encryptParam.pvEncryptionAuxInfo.DangerousGetHandle();
            } 

            encodeInfo.cRecipients = (uint) recipients.Count; 
 
            if (encryptParam.useCms) {
                SetCmsRecipientParams(recipients, this.Certificates, this.UnprotectedAttributes, this.ContentEncryptionAlgorithm, ref encryptParam); 
                encodeInfo.rgCmsRecipients = encryptParam.rgpRecipients.DangerousGetHandle();
                if (encryptParam.rgCertEncoded != null && !encryptParam.rgCertEncoded.IsInvalid) {
                    encodeInfo.cCertEncoded = (uint) this.Certificates.Count;
                    encodeInfo.rgCertEncoded = encryptParam.rgCertEncoded.DangerousGetHandle(); 
                }
                if (encryptParam.rgUnprotectedAttr != null && !encryptParam.rgUnprotectedAttr.IsInvalid) { 
                    encodeInfo.cUnprotectedAttr = (uint) this.UnprotectedAttributes.Count; 
                    encodeInfo.rgUnprotectedAttr = encryptParam.rgUnprotectedAttr.DangerousGetHandle();
                } 
            }
            else {
                SetPkcs7RecipientParams(recipients, ref encryptParam);
                encodeInfo.rgpRecipients = encryptParam.rgpRecipients.DangerousGetHandle(); 
            }
 
            Marshal.StructureToPtr(encodeInfo, ceei.DangerousGetHandle(), false); 

            try { 
                SafeCryptMsgHandle safeCryptMsgHandle = CAPI.CryptMsgOpenToEncode(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                                                  0,
                                                                                  CAPI.CMSG_ENVELOPED,
                                                                                  ceei.DangerousGetHandle(), 
                                                                                  this.ContentInfo.ContentType.Value,
                                                                                  IntPtr.Zero); 
                if (safeCryptMsgHandle == null || safeCryptMsgHandle.IsInvalid) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
 
                if (m_safeCryptMsgHandle != null && !m_safeCryptMsgHandle.IsInvalid) {
                    m_safeCryptMsgHandle.Dispose();
                }
 
                m_safeCryptMsgHandle = safeCryptMsgHandle;
            } 
            finally { 
                Marshal.DestroyStructure(ceei.DangerousGetHandle(), typeof(CAPI.CMSG_ENVELOPED_ENCODE_INFO));
                ceei.Dispose(); 
            }

            byte[] encodedContent = new byte[0];
            if (String.Compare(this.ContentInfo.ContentType.Value, CAPI.szOID_RSA_data, StringComparison.OrdinalIgnoreCase) == 0) { 
                byte[] content = this.ContentInfo.Content;
                fixed (byte * pbContent = content) { 
                    CAPI.CRYPTOAPI_BLOB dataBlob = new CAPI.CRYPTOAPI_BLOB(); 
                    dataBlob.cbData = (uint) content.Length;
                    dataBlob.pbData = new IntPtr(pbContent); 
                    if (!CAPI.EncodeObject(new IntPtr(CAPI.X509_OCTET_STRING), new IntPtr(&dataBlob), out encodedContent))
                        throw new CryptographicException(Marshal.GetLastWin32Error());
                }
            } 
            else {
                encodedContent = this.ContentInfo.Content; 
            } 
            if (encodedContent.Length > 0) {
                if (!CAPI.CryptMsgUpdate(m_safeCryptMsgHandle, encodedContent, (uint) encodedContent.Length, true)) 
                    throw new CryptographicException(Marshal.GetLastWin32Error());
            }

            // Keep alive 
            GC.KeepAlive(encryptParam);
            GC.KeepAlive(recipients); 
        } 

        // 
        // Private static methods.
        //

        private static unsafe SafeCryptMsgHandle OpenToDecode (byte[] encodedMessage) { 
            SafeCryptMsgHandle safeCryptMsgHandle = null;
 
            // Open the message for decode. 
            safeCryptMsgHandle = CAPI.CryptMsgOpenToDecode(CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                           0, 
                                                           0,
                                                           IntPtr.Zero,
                                                           IntPtr.Zero,
                                                           IntPtr.Zero); 
            if (safeCryptMsgHandle == null || safeCryptMsgHandle.IsInvalid)
                throw new CryptographicException(Marshal.GetLastWin32Error()); 
 
            // ---- the message.
            if (!CAPI.CryptMsgUpdate(safeCryptMsgHandle, encodedMessage, (uint) encodedMessage.Length, true)) 
                throw new CryptographicException(Marshal.GetLastWin32Error());

            // Make sure this is EnvelopedData type.
            if (CAPI.CMSG_ENVELOPED != PkcsUtils.GetMessageType(safeCryptMsgHandle)) 
                throw new CryptographicException(CAPI.CRYPT_E_INVALID_MSG_TYPE);
 
            return safeCryptMsgHandle; 
        }
 
        private static unsafe int /* HRESULT */ GetCspParams (RecipientInfo recipientInfo,
                                                              X509Certificate2Collection extraStore,
                                                              ref CMSG_DECRYPT_PARAM cmsgDecryptParam) {
            int hr = CAPI.CRYPT_E_RECIPIENT_NOT_FOUND; 
            SafeCertContextHandle safeCertContextHandle = SafeCertContextHandle.InvalidHandle;
            SafeCertStoreHandle safeCertStoreHandle = BuildDecryptorStore(extraStore); 
 
            switch (recipientInfo.Type) {
            case RecipientInfoType.KeyTransport: 
                if (recipientInfo.SubType == RecipientSubType.Pkcs7KeyTransport) {
                    safeCertContextHandle = CAPI.CertFindCertificateInStore(safeCertStoreHandle,
                                                                            CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                                            0, 
                                                                            CAPI.CERT_FIND_SUBJECT_CERT,
                                                                            recipientInfo.pCmsgRecipientInfo.DangerousGetHandle(), 
                                                                            SafeCertContextHandle.InvalidHandle); 
                }
                else { 
                    CAPI.CMSG_KEY_TRANS_RECIPIENT_INFO keyTrans = (CAPI.CMSG_KEY_TRANS_RECIPIENT_INFO) recipientInfo.CmsgRecipientInfo;
                    safeCertContextHandle = CAPI.CertFindCertificateInStore(safeCertStoreHandle,
                                                                            CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING,
                                                                            0, 
                                                                            CAPI.CERT_FIND_CERT_ID,
                                                                            new IntPtr((byte *) &keyTrans.RecipientId), 
                                                                            SafeCertContextHandle.InvalidHandle); 
                }
                break; 

            case RecipientInfoType.KeyAgreement:
                KeyAgreeRecipientInfo keyAgree = (KeyAgreeRecipientInfo) recipientInfo;
                CAPI.CERT_ID recipientId = keyAgree.RecipientId; 
                safeCertContextHandle = CAPI.CertFindCertificateInStore(safeCertStoreHandle,
                                                                        CAPI.X509_ASN_ENCODING | CAPI.PKCS_7_ASN_ENCODING, 
                                                                        0, 
                                                                        CAPI.CERT_FIND_CERT_ID,
                                                                        new IntPtr(&recipientId), 
                                                                        SafeCertContextHandle.InvalidHandle);
                break;

            default: // Others not supported. 
                hr = CAPI.E_NOTIMPL;
                break; 
            } 

            // Acquire CSP if the recipient's cert is found. 
            if (safeCertContextHandle != null && !safeCertContextHandle.IsInvalid) {
                SafeCryptProvHandle safeCryptProvHandle = SafeCryptProvHandle.InvalidHandle;
                uint keySpec = 0;
                bool freeCsp = false; 

                // Check to see if KEY_PROV_INFO contains "MS Base ..." 
                // If so, acquire "MS Enhanced..." or "MS Strong". 
                // if failed, then use CryptAcquireCertificatePrivateKey
                CspParameters parameters = new CspParameters(); 
                if (X509Utils.GetPrivateKeyInfo(safeCertContextHandle, ref parameters) == false)
                    throw new CryptographicException(Marshal.GetLastWin32Error());

                if (String.Compare(parameters.ProviderName, CAPI.MS_DEF_PROV, StringComparison.OrdinalIgnoreCase) == 0) { 
                    if (CAPI.CryptAcquireContext(ref safeCryptProvHandle, parameters.KeyContainerName, CAPI.MS_ENHANCED_PROV, CAPI.PROV_RSA_FULL, 0) ||
                        CAPI.CryptAcquireContext(ref safeCryptProvHandle, parameters.KeyContainerName, CAPI.MS_STRONG_PROV,   CAPI.PROV_RSA_FULL, 0)) { 
                            cmsgDecryptParam.safeCryptProvHandle = safeCryptProvHandle; 
                    }
                } 

                cmsgDecryptParam.safeCertContextHandle = safeCertContextHandle;
                cmsgDecryptParam.keySpec = (uint)parameters.KeyNumber;
                hr = CAPI.S_OK; 

                if ((safeCryptProvHandle == null) || (safeCryptProvHandle.IsInvalid)) { 
                    if (CAPI.CryptAcquireCertificatePrivateKey(safeCertContextHandle, 
                                                            CAPI.CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CAPI.CRYPT_ACQUIRE_USE_PROV_INFO_FLAG,
                                                            IntPtr.Zero, 
                                                            ref safeCryptProvHandle,
                                                            ref keySpec,
                                                            ref freeCsp)) {
                        if (!freeCsp) { 
                            GC.SuppressFinalize(safeCryptProvHandle);
                        } 
 
                        cmsgDecryptParam.safeCryptProvHandle = safeCryptProvHandle;
                    } 
                    else {
                        hr = Marshal.GetHRForLastWin32Error();
                    }
                } 
            }
 
            return hr; 
        }
 
        private static unsafe void SetCspParams (AlgorithmIdentifier contentEncryptionAlgorithm, ref CMSG_ENCRYPT_PARAM encryptParam) {

            encryptParam.safeCryptProvHandle = SafeCryptProvHandle.InvalidHandle;
            encryptParam.pvEncryptionAuxInfo = SafeLocalAllocHandle.InvalidHandle; 

            // Try with CRYPT_VERIFYCONTEXT first, and then without in case this is Win9x platform. 
            SafeCryptProvHandle hCryptProv = SafeCryptProvHandle.InvalidHandle; 
            if (!CAPI.CryptAcquireContext(ref hCryptProv, IntPtr.Zero, IntPtr.Zero, CAPI.PROV_RSA_FULL, CAPI.CRYPT_VERIFYCONTEXT) &&
                !CAPI.CryptAcquireContext(ref hCryptProv, IntPtr.Zero, IntPtr.Zero, CAPI.PROV_RSA_FULL, 0)) { 
                throw new CryptographicException(Marshal.GetLastWin32Error());
            }

            uint algId = X509Utils.OidToAlgId(contentEncryptionAlgorithm.Oid.Value); 
            if (algId == CAPI.CALG_RC2 || algId == CAPI.CALG_RC4) {
                CAPI.CMSG_RC2_AUX_INFO auxInfo = new CAPI.CMSG_RC2_AUX_INFO(Marshal.SizeOf(typeof(CAPI.CMSG_RC2_AUX_INFO))); 
                uint keyLength = (uint) contentEncryptionAlgorithm.KeyLength; 
                if (keyLength == 0) {
                    keyLength = (uint) PkcsUtils.GetMaxKeyLength(hCryptProv, algId); 
                }
                auxInfo.dwBitLen = keyLength;
                SafeLocalAllocHandle pvAuxInfo = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_RC2_AUX_INFO))));
                Marshal.StructureToPtr(auxInfo, pvAuxInfo.DangerousGetHandle(), false); 
                encryptParam.pvEncryptionAuxInfo = pvAuxInfo;
            } 
 
            encryptParam.safeCryptProvHandle = hCryptProv;
        } 

        private static unsafe void SetCmsRecipientParams(CmsRecipientCollection           recipients,
                                                         X509Certificate2Collection      certificates,
                                                         CryptographicAttributeObjectCollection unprotectedAttributes, 
                                                         AlgorithmIdentifier              contentEncryptionAlgorithm,
                                                         ref CMSG_ENCRYPT_PARAM           encryptParam) { 
            int index = 0; 
            uint[] recipientInfoTypes = new uint[recipients.Count];
            int cKeyAgree = 0; 
            int reiSize = recipients.Count * Marshal.SizeOf(typeof(CAPI.CMSG_RECIPIENT_ENCODE_INFO));
            int totalSize = reiSize;

            for (index = 0; index < recipients.Count; index++) { 
                recipientInfoTypes[index] = (uint) PkcsUtils.GetRecipientInfoType(recipients[index].Certificate);
 
                if (recipientInfoTypes[index] == CAPI.CMSG_KEY_TRANS_RECIPIENT) { 
                    totalSize += Marshal.SizeOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO));
                } 
                else if (recipientInfoTypes[index] == CAPI.CMSG_KEY_AGREE_RECIPIENT) {
                    cKeyAgree++;
                    totalSize += Marshal.SizeOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO));
                } 
                else {
                    throw new CryptographicException(CAPI.CRYPT_E_UNKNOWN_ALGO); 
                } 
            }
 
            encryptParam.rgpRecipients = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(totalSize));
            encryptParam.rgCertEncoded = SafeLocalAllocHandle.InvalidHandle;
            encryptParam.rgUnprotectedAttr = SafeLocalAllocHandle.InvalidHandle;
            encryptParam.rgSubjectKeyIdentifier = new SafeLocalAllocHandle[recipients.Count]; 
            encryptParam.rgszObjId = new SafeLocalAllocHandle[recipients.Count];
 
            if (cKeyAgree > 0) { 
                encryptParam.rgszKeyWrapObjId = new SafeLocalAllocHandle[cKeyAgree];
                encryptParam.rgKeyWrapAuxInfo = new SafeLocalAllocHandle[cKeyAgree]; 
                encryptParam.rgEphemeralIdentifier = new SafeLocalAllocHandle[cKeyAgree];
                encryptParam.rgszEphemeralObjId = new SafeLocalAllocHandle[cKeyAgree];
                encryptParam.rgUserKeyingMaterial = new SafeLocalAllocHandle[cKeyAgree];
                encryptParam.prgpEncryptedKey = new SafeLocalAllocHandle[cKeyAgree]; 
                encryptParam.rgpEncryptedKey = new SafeLocalAllocHandle[cKeyAgree];
            } 
 
            // Create encode certs array.
            if (certificates.Count > 0) { 
                encryptParam.rgCertEncoded = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(certificates.Count * Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB))));
                for (index = 0; index < certificates.Count; index++) {
                    CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(X509Utils.GetCertContext(certificates[index]).DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT));
                    CAPI.CRYPTOAPI_BLOB * pBlob = (CAPI.CRYPTOAPI_BLOB *) new IntPtr((long) encryptParam.rgCertEncoded.DangerousGetHandle() + 
                                                                                     (index * Marshal.SizeOf(typeof(CAPI.CRYPTOAPI_BLOB))));
                    pBlob->cbData = pCertContext.cbCertEncoded; 
                    pBlob->pbData = pCertContext.pbCertEncoded; 
                }
            } 

            // Create unprotected attributes array.
            if (unprotectedAttributes.Count > 0) {
                encryptParam.rgUnprotectedAttr = new SafeLocalAllocHandle(PkcsUtils.CreateCryptAttributes(unprotectedAttributes)); 
            }
 
            // pKeyInfo = CMSG_ENVELOPED_ENCODE_INFO.rgCmsRecipients 
            cKeyAgree = 0;
            IntPtr pKeyInfo = new IntPtr((long) encryptParam.rgpRecipients.DangerousGetHandle() + reiSize); 
            for (index = 0; index < recipients.Count; index++) {
                CmsRecipient recipient = recipients[index];
                X509Certificate2 certificate = recipient.Certificate;
                CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(X509Utils.GetCertContext(certificate).DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT)); 
                CAPI.CERT_INFO certInfo = (CAPI.CERT_INFO) Marshal.PtrToStructure(pCertContext.pCertInfo, typeof(CAPI.CERT_INFO));
 
                CAPI.CMSG_RECIPIENT_ENCODE_INFO * pEncodeInfo = (CAPI.CMSG_RECIPIENT_ENCODE_INFO *) new IntPtr((long) encryptParam.rgpRecipients.DangerousGetHandle() + 
                                                                                                               (index * Marshal.SizeOf(typeof(CAPI.CMSG_RECIPIENT_ENCODE_INFO))));
                // CMSG_RECIPIENT_ENCODE_INFO.dwRecipientChoice 
                pEncodeInfo->dwRecipientChoice = (uint) recipientInfoTypes[index];

                // CMSG_RECIPIENT_ENCODE_INFO.pRecipientInfo (pKeyTrans or pKeyAgree)
                pEncodeInfo->pRecipientInfo = pKeyInfo; 

                if (recipientInfoTypes[index] == CAPI.CMSG_KEY_TRANS_RECIPIENT) { 
                    // Fill in CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO. 

                    // cbSize 
                    IntPtr pcbSize = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO), "cbSize"));
                    Marshal.WriteInt32(pcbSize, Marshal.SizeOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO)));

                    // KeyEncryptionAlgorithm 
                    IntPtr pKeyEncryptionAlgorithm = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO), "KeyEncryptionAlgorithm"));
 
                    byte[] objId = Encoding.ASCII.GetBytes(certInfo.SubjectPublicKeyInfo.Algorithm.pszObjId); 
                    encryptParam.rgszObjId[index] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(objId.Length + 1));
                    Marshal.Copy(objId, 0, encryptParam.rgszObjId[index].DangerousGetHandle(), objId.Length); 

                    // KeyEncryptionAlgorithm.pszObjId
                    IntPtr pszObjId = new IntPtr((long) pKeyEncryptionAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "pszObjId"));
                    Marshal.WriteIntPtr(pszObjId, encryptParam.rgszObjId[index].DangerousGetHandle()); 

                    // KeyEncryptionAlgorithm.Parameters 
                    IntPtr pParameters = new IntPtr((long) pKeyEncryptionAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "Parameters")); 

                    // KeyEncryptionAlgorithm.Parameters.cbData 
                    IntPtr pcbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
                    Marshal.WriteInt32(pcbData, (int) certInfo.SubjectPublicKeyInfo.Algorithm.Parameters.cbData);

                    // KeyEncryptionAlgorithm.Parameters.pbData 
                    IntPtr ppbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData"));
                    Marshal.WriteIntPtr(ppbData, certInfo.SubjectPublicKeyInfo.Algorithm.Parameters.pbData); 
 
                    // Skip pvKeyEncryptionAuxInfo
                    // Skip hCryptProv 

                    // RecipientPublicKey
                    IntPtr pRecipientPublicKey = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO), "RecipientPublicKey"));
 
                    // RecipientPublicKey.cbData
                    pcbData = new IntPtr((long) pRecipientPublicKey + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_BIT_BLOB), "cbData")); 
                    Marshal.WriteInt32(pcbData, (int) certInfo.SubjectPublicKeyInfo.PublicKey.cbData); 

                    // RecipientPublicKey.pbData 
                    ppbData = new IntPtr((long) pRecipientPublicKey + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_BIT_BLOB), "pbData"));
                    Marshal.WriteIntPtr(ppbData, certInfo.SubjectPublicKeyInfo.PublicKey.pbData);

                    // RecipientPublicKey.cUnusedBits 
                    IntPtr pcUnusedBIts = new IntPtr((long) pRecipientPublicKey + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_BIT_BLOB), "cUnusedBits"));
                    Marshal.WriteInt32(pcUnusedBIts, (int) certInfo.SubjectPublicKeyInfo.PublicKey.cUnusedBits); 
 
                    // RecipientId
                    IntPtr pRecipientId = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO), "RecipientId")); 
                    if (recipient.RecipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier) {
                        uint cbData = 0;
                        SafeLocalAllocHandle pbData = SafeLocalAllocHandle.InvalidHandle;
                        if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate), 
                                                                    CAPI.CERT_KEY_IDENTIFIER_PROP_ID,
                                                                    pbData, 
                                                                    ref cbData)) 
                            throw new CryptographicException(Marshal.GetLastWin32Error());
 
                        pbData = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbData));

                        if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate),
                                                                    CAPI.CERT_KEY_IDENTIFIER_PROP_ID, 
                                                                    pbData,
                                                                    ref cbData)) 
                            throw new CryptographicException(Marshal.GetLastWin32Error()); 

                        encryptParam.rgSubjectKeyIdentifier[index] = pbData; 

                        // RecipientId.dwIdChoice
                        IntPtr pdwIdChoice = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "dwIdChoice"));
                        Marshal.WriteInt32(pdwIdChoice, (int) CAPI.CERT_ID_KEY_IDENTIFIER); 

                        // RecipientId.KeyId 
                        IntPtr pKeyId = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "Value")); 

                        // RecipientId.KeyId.cbData 
                        pcbData = new IntPtr((long) pKeyId + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
                        Marshal.WriteInt32(pcbData, (int) cbData);

                        // RecipientId.KeyId.pbData 
                        ppbData = new IntPtr((long) pKeyId + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData"));
                        Marshal.WriteIntPtr(ppbData, pbData.DangerousGetHandle()); 
                    } 
                    else {
                        // RecipientId.dwIdChoice 
                        IntPtr pdwIdChoice = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "dwIdChoice"));
                        Marshal.WriteInt32(pdwIdChoice, (int) CAPI.CERT_ID_ISSUER_SERIAL_NUMBER);

                        // RecipientId.IssuerSerialNumber 
                        IntPtr pIssuerSerialNumber = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "Value"));
 
                        // RecipientId.IssuerSerialNumber.Issuer 
                        IntPtr pIssuer = new IntPtr((long) pIssuerSerialNumber + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ISSUER_SERIAL_NUMBER), "Issuer"));
 
                        // RecipientId.IssuerSerialNumber.Issuer.cbData
                        pcbData = new IntPtr((long) pIssuer + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
                        Marshal.WriteInt32(pcbData, (int) certInfo.Issuer.cbData);
 
                        // RecipientId.IssuerSerialNumber.Issuer.pbData
                        ppbData = new IntPtr((long) pIssuer + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData")); 
                        Marshal.WriteIntPtr(ppbData, certInfo.Issuer.pbData); 

                        // RecipientId.IssuerSerialNumber.SerialNumber 
                        IntPtr pSerialNumber = new IntPtr((long) pIssuerSerialNumber + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ISSUER_SERIAL_NUMBER), "SerialNumber"));

                        // RecipientId.IssuerSerialNumber.SerialNumber.cbData
                        pcbData = new IntPtr((long) pSerialNumber + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData")); 
                        Marshal.WriteInt32(pcbData, (int) certInfo.SerialNumber.cbData);
 
                        // RecipientId.IssuerSerialNumber.SerialNumber.pbData 
                        ppbData = new IntPtr((long) pSerialNumber + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData"));
                        Marshal.WriteIntPtr(ppbData, certInfo.SerialNumber.pbData); 
                    }
                    pKeyInfo = new IntPtr((long) pKeyInfo + Marshal.SizeOf(typeof(CAPI.CMSG_KEY_TRANS_RECIPIENT_ENCODE_INFO)));
                }
                else if (recipientInfoTypes[index] == CAPI.CMSG_KEY_AGREE_RECIPIENT) { 
                    // Fill in CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO.
 
                    // cbSize 
                    IntPtr pcbSize = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "cbSize"));
                    Marshal.WriteInt32(pcbSize, Marshal.SizeOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO))); 

                    // KeyEncryptionAlgorithm
                    IntPtr pKeyEncryptionAlgorithm = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "KeyEncryptionAlgorithm"));
 
                    byte[] objId = Encoding.ASCII.GetBytes(CAPI.szOID_RSA_SMIMEalgESDH);
                    encryptParam.rgszObjId[index] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(objId.Length + 1)); 
                    Marshal.Copy(objId, 0, encryptParam.rgszObjId[index].DangerousGetHandle(), objId.Length); 

                    // KeyEncryptionAlgorithm.pszObjId 
                    IntPtr pszObjId = new IntPtr((long) pKeyEncryptionAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "pszObjId"));
                    Marshal.WriteIntPtr(pszObjId, encryptParam.rgszObjId[index].DangerousGetHandle());

                    // Skip KeyEncryptionAlgorithm.Parameters 
                    // Skip pvKeyEncryptionAuxInfo
 
                    // KeyWrapAlgorithm 
                    IntPtr pKeyWrapAlgorithm = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "KeyWrapAlgorithm"));
 
                    uint algId = X509Utils.OidToAlgId(contentEncryptionAlgorithm.Oid.Value);
                    if (algId == CAPI.CALG_RC2) {
                        objId = Encoding.ASCII.GetBytes(CAPI.szOID_RSA_SMIMEalgCMSRC2wrap);
                    } 
                    else {
                        objId = Encoding.ASCII.GetBytes(CAPI.szOID_RSA_SMIMEalgCMS3DESwrap); 
                    } 
                    encryptParam.rgszKeyWrapObjId[cKeyAgree] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(objId.Length + 1));
                    Marshal.Copy(objId, 0, encryptParam.rgszKeyWrapObjId[cKeyAgree].DangerousGetHandle(), objId.Length); 

                    // KeyWrapAlgorithm.pszObjId
                    pszObjId = new IntPtr((long) pKeyWrapAlgorithm + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "pszObjId"));
                    Marshal.WriteIntPtr(pszObjId, encryptParam.rgszKeyWrapObjId[cKeyAgree].DangerousGetHandle()); 

                    // Skip KeyWrapAlgorithm.Parameters 
 
                    // Fill in pvKeyWrapAuxInfo for RC2.
                    if (algId == CAPI.CALG_RC2) { 
                        IntPtr pKeyWrapAuxInfo = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "pvKeyWrapAuxInfo"));
                        Marshal.WriteIntPtr(pKeyWrapAuxInfo, encryptParam.pvEncryptionAuxInfo.DangerousGetHandle());
                    }
 
                    // Skip hCryptProv
                    // Skip dwKeySpec 
 
                    // dwKeyChoice
                    IntPtr pdwKeyChoice = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "dwKeyChoice")); 
                    Marshal.WriteInt32(pdwKeyChoice, (int) CAPI.CMSG_KEY_AGREE_EPHEMERAL_KEY_CHOICE);

                    // pEphemeralAlgorithm
                    IntPtr pEphemeralAlgorithm = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "pEphemeralAlgorithmOrSenderId")); 
                    encryptParam.rgEphemeralIdentifier[cKeyAgree] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER))));
                    Marshal.WriteIntPtr(pEphemeralAlgorithm, encryptParam.rgEphemeralIdentifier[cKeyAgree].DangerousGetHandle()); 
 
                    // pEphemeralAlgorithm.pszObjId
                    objId = Encoding.ASCII.GetBytes(certInfo.SubjectPublicKeyInfo.Algorithm.pszObjId); 
                    encryptParam.rgszEphemeralObjId[cKeyAgree] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(objId.Length + 1));
                    Marshal.Copy(objId, 0, encryptParam.rgszEphemeralObjId[cKeyAgree].DangerousGetHandle(), objId.Length);

                    pszObjId = new IntPtr((long) encryptParam.rgEphemeralIdentifier[cKeyAgree].DangerousGetHandle() + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "pszObjId")); 
                    Marshal.WriteIntPtr(pszObjId, encryptParam.rgszEphemeralObjId[cKeyAgree].DangerousGetHandle());
 
                    // pEphemeralAlgorithm.Parameters 
                    IntPtr pParameters = new IntPtr((long) encryptParam.rgEphemeralIdentifier[cKeyAgree].DangerousGetHandle() + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_ALGORITHM_IDENTIFIER), "Parameters"));
 
                    // pEphemeralAlgorithm.Parameters.cbData
                    IntPtr pcbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
                    Marshal.WriteInt32(pcbData, (int) certInfo.SubjectPublicKeyInfo.Algorithm.Parameters.cbData);
 
                    // pEphemeralAlgorithm.Parameters.pbData
                    IntPtr ppbData = new IntPtr((long) pParameters + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData")); 
                    Marshal.WriteIntPtr(ppbData, certInfo.SubjectPublicKeyInfo.Algorithm.Parameters.pbData); 

                    // Skip UserKeyingMaterial 

                    // cRecipientEncryptedKeys
                    IntPtr pcRecipientEncryptedKeys = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "cRecipientEncryptedKeys"));
                    Marshal.WriteInt32(pcRecipientEncryptedKeys, 1); 

                    // rgpRecipientEncryptedKeys 
                    encryptParam.prgpEncryptedKey[cKeyAgree] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(IntPtr)))); 
                    IntPtr prgpRecipientEncryptedKeys = new IntPtr((long) pKeyInfo + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO), "rgpRecipientEncryptedKeys"));
                    Marshal.WriteIntPtr(prgpRecipientEncryptedKeys, encryptParam.prgpEncryptedKey[cKeyAgree].DangerousGetHandle()); 
                    encryptParam.rgpEncryptedKey[cKeyAgree] = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(Marshal.SizeOf(typeof(CAPI.CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO))));
                    Marshal.WriteIntPtr(encryptParam.prgpEncryptedKey[cKeyAgree].DangerousGetHandle(), encryptParam.rgpEncryptedKey[cKeyAgree].DangerousGetHandle());

                    // rgpRecipientEncryptedKeys.cbSize 
                    pcbSize = new IntPtr((long) encryptParam.rgpEncryptedKey[cKeyAgree].DangerousGetHandle() + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO), "cbSize"));
                    Marshal.WriteInt32(pcbSize, Marshal.SizeOf(typeof(CAPI.CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO))); 
 
                    // rgpRecipientEncryptedKeys.RecipientPublicKey
                    IntPtr pRecipientPublicKey = new IntPtr((long) encryptParam.rgpEncryptedKey[cKeyAgree].DangerousGetHandle() + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO), "RecipientPublicKey")); 

                    // rgpRecipientEncryptedKeys.RecipientPublicKey.cbData
                    pcbData = new IntPtr((long) pRecipientPublicKey + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_BIT_BLOB), "cbData"));
                    Marshal.WriteInt32(pcbData, (int) certInfo.SubjectPublicKeyInfo.PublicKey.cbData); 

                    // rgpRecipientEncryptedKeys.RecipientPublicKey.pbData 
                    ppbData = new IntPtr((long) pRecipientPublicKey + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_BIT_BLOB), "pbData")); 
                    Marshal.WriteIntPtr(ppbData, certInfo.SubjectPublicKeyInfo.PublicKey.pbData);
 
                    // rgpRecipientEncryptedKeys.RecipientPublicKey.cUnusedBits
                    IntPtr pcUnusedBits = new IntPtr((long) pRecipientPublicKey + (long) Marshal.OffsetOf(typeof(CAPI.CRYPT_BIT_BLOB), "cUnusedBits"));
                    Marshal.WriteInt32(pcUnusedBits, (int) certInfo.SubjectPublicKeyInfo.PublicKey.cUnusedBits);
 
                    // rgpRecipientEncryptedKeys.RecipientId
                    IntPtr pRecipientId = new IntPtr((long) encryptParam.rgpEncryptedKey[cKeyAgree].DangerousGetHandle() + (long) Marshal.OffsetOf(typeof(CAPI.CMSG_RECIPIENT_ENCRYPTED_KEY_ENCODE_INFO), "RecipientId")); 
 
                    // rgpRecipientEncryptedKeys.RecipientId.dwIdChoice
                    IntPtr pdwIdChoice = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "dwIdChoice")); 

                    if (recipient.RecipientIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier) {
                        Marshal.WriteInt32(pdwIdChoice, (int) CAPI.CERT_ID_KEY_IDENTIFIER);
 
                        // rgpRecipientEncryptedKeys.RecipientId.KeyId
                        IntPtr pKeyId = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "Value")); 
 
                        uint cbKeyId = 0;
                        SafeLocalAllocHandle pbKeyId = SafeLocalAllocHandle.InvalidHandle; 
                        if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate),
                                                                    CAPI.CERT_KEY_IDENTIFIER_PROP_ID,
                                                                    pbKeyId,
                                                                    ref cbKeyId)) 
                            throw new CryptographicException(Marshal.GetLastWin32Error());
 
                        pbKeyId = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(cbKeyId)); 
                        if (!CAPI.CertGetCertificateContextProperty(X509Utils.GetCertContext(certificate),
                                                                    CAPI.CERT_KEY_IDENTIFIER_PROP_ID, 
                                                                    pbKeyId,
                                                                    ref cbKeyId))
                            throw new CryptographicException(Marshal.GetLastWin32Error());
 
                        encryptParam.rgSubjectKeyIdentifier[cKeyAgree] = pbKeyId;
 
                        // rgpRecipientEncryptedKeys.RecipientId.KeyId.cbData 
                        pcbData = new IntPtr((long) pKeyId + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData"));
                        Marshal.WriteInt32(pcbData, (int) cbKeyId); 

                        // rgpRecipientEncryptedKeys.RecipientId.KeyId.pbData
                        ppbData = new IntPtr((long) pKeyId + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData"));
                        Marshal.WriteIntPtr(ppbData, pbKeyId.DangerousGetHandle()); 
                    }
                    else { 
                        Marshal.WriteInt32(pdwIdChoice, (int) CAPI.CERT_ID_ISSUER_SERIAL_NUMBER); 

                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber 
                        IntPtr pIssuerSerial = new IntPtr((long) pRecipientId + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ID), "Value"));

                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber.Issuer
                        IntPtr pIssuer = new IntPtr((long) pIssuerSerial + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ISSUER_SERIAL_NUMBER), "Issuer")); 

                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber.Issuer.cbData 
                        pcbData = new IntPtr((long) pIssuer + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData")); 
                        Marshal.WriteInt32(pcbData, (int) certInfo.Issuer.cbData);
 
                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber.Issuer.pbData
                        ppbData = new IntPtr((long) pIssuer + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData"));
                        Marshal.WriteIntPtr(ppbData, certInfo.Issuer.pbData);
 
                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber.SerialNumber
                        IntPtr pSerialNumber = new IntPtr((long) pIssuerSerial + (long) Marshal.OffsetOf(typeof(CAPI.CERT_ISSUER_SERIAL_NUMBER), "SerialNumber")); 
 
                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber.SerialNumber.cbData
                        pcbData = new IntPtr((long) pSerialNumber + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "cbData")); 
                        Marshal.WriteInt32(pcbData, (int) certInfo.SerialNumber.cbData);

                        // rgpRecipientEncryptedKeys.RecipientId.IssuerSerialNumber.SerialNumber.pbData
                        ppbData = new IntPtr((long) pSerialNumber + (long) Marshal.OffsetOf(typeof(CAPI.CRYPTOAPI_BLOB), "pbData")); 
                        Marshal.WriteIntPtr(ppbData, certInfo.SerialNumber.pbData);
                    } 
 
                    // Bump key agree count.
                    cKeyAgree++; 
                    pKeyInfo = new IntPtr((long) pKeyInfo + Marshal.SizeOf(typeof(CAPI.CMSG_KEY_AGREE_RECIPIENT_ENCODE_INFO)));
                }
                else {
                    // Should never get here! 
                    Debug.Assert(false);
                } 
            } 
        }
 
        private static unsafe void SetPkcs7RecipientParams (CmsRecipientCollection recipients,
                                                            ref CMSG_ENCRYPT_PARAM encryptParam) {
            int index = 0;
            uint totalSize = (uint) recipients.Count * (uint) Marshal.SizeOf(typeof(IntPtr)); 

            encryptParam.rgpRecipients = CAPI.LocalAlloc(CAPI.LPTR, new IntPtr(totalSize)); 
 
            IntPtr pCertInfo = encryptParam.rgpRecipients.DangerousGetHandle();
 
            for (index = 0; index < recipients.Count; index++) {
                CAPI.CERT_CONTEXT pCertContext = (CAPI.CERT_CONTEXT) Marshal.PtrToStructure(X509Utils.GetCertContext(recipients[index].Certificate).DangerousGetHandle(), typeof(CAPI.CERT_CONTEXT));

                Marshal.WriteIntPtr(pCertInfo, pCertContext.pCertInfo); 
                pCertInfo = new IntPtr((long) pCertInfo + Marshal.SizeOf(typeof(IntPtr)));
            } 
        } 

        private static unsafe SafeCertStoreHandle BuildDecryptorStore (X509Certificate2Collection extraStore) { 
            // Build store where to find recipient's certificate.
            X509Certificate2Collection recipientStore = new X509Certificate2Collection();

            // Include CU and LM MY stores. 
            try {
                X509Store cuMy = new X509Store("MY", StoreLocation.CurrentUser); 
                cuMy.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly | OpenFlags.IncludeArchived); 
                recipientStore.AddRange(cuMy.Certificates);
 
            }
            catch (SecurityException) {
                // X509Store.Open() may not have permission. Ignore.
            } 
            try {
                X509Store lmMy = new X509Store("MY", StoreLocation.LocalMachine); 
                lmMy.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly | OpenFlags.IncludeArchived); 
                recipientStore.AddRange(lmMy.Certificates);
            } 
            catch (SecurityException) {
                // Ignore. May be in extra store.
            }
 
            // Finally, include extra store, if specified.
            if (extraStore != null) { 
                recipientStore.AddRange(extraStore); 
            }
 
            if (recipientStore.Count == 0)
                throw new CryptographicException(CAPI.CRYPT_E_RECIPIENT_NOT_FOUND);

            // Return memory store handle. 
            return X509Utils.ExportToMemoryStore(recipientStore);
        } 
 
        private static unsafe SafeCertStoreHandle BuildOriginatorStore (X509Certificate2Collection bagOfCerts, X509Certificate2Collection extraStore) {
            // Build store where to find originator's certificate. 
            X509Certificate2Collection originatorStore = new X509Certificate2Collection();

            // Include CU and LM MY stores.
            try { 
                X509Store cuMy = new X509Store("AddressBook", StoreLocation.CurrentUser);
                cuMy.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly | OpenFlags.IncludeArchived); 
                originatorStore.AddRange(cuMy.Certificates); 

            } 
            catch (SecurityException) {
                // X509Store.Open() may not have permission. Ignore.
            }
            try { 
                X509Store lmMy = new X509Store("AddressBook", StoreLocation.LocalMachine);
                lmMy.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly | OpenFlags.IncludeArchived); 
                originatorStore.AddRange(lmMy.Certificates); 
            }
            catch (SecurityException) { 
                // Ignore. May be in bag of certs or extra store.
            }

            // Finally, include bag of certs and extra store, if specified. 
            if (bagOfCerts != null) {
                originatorStore.AddRange(bagOfCerts); 
            } 
            if (extraStore != null) {
                originatorStore.AddRange(extraStore); 
            }

            if (originatorStore.Count == 0)
                throw new CryptographicException(CAPI.CRYPT_E_NOT_FOUND); 

            // Return memory store handle. 
            return X509Utils.ExportToMemoryStore(originatorStore); 
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK