public static SafeCryptMsgHandle CreateCryptMsgHandleToEncode(CmsRecipientCollection recipients, Oid innerContentType, AlgorithmIdentifier contentEncryptionAlgorithm, X509Certificate2Collection originatorCerts, CryptographicAttributeObjectCollection unprotectedAttributes) { using (HeapBlockRetainer hb = new HeapBlockRetainer()) { // Deep copy the CmsRecipients (and especially their underlying X509Certificate2 objects). This will prevent malicious callers from altering them or disposing them while we're performing // unsafe memory crawling inside them. recipients = recipients.DeepCopy(); // We must keep all the certificates inside recipients alive until the call to CryptMsgOpenToEncode() finishes. The CMSG_ENVELOPED_ENCODE_INFO* structure we passed to it // contains direct pointers to memory owned by the CERT_INFO memory block whose lifetime is that of the certificate. hb.KeepAlive(recipients); unsafe { CMSG_ENVELOPED_ENCODE_INFO* pEnvelopedEncodeInfo = CreateCmsEnvelopedEncodeInfo(recipients, contentEncryptionAlgorithm, originatorCerts, unprotectedAttributes, hb); SafeCryptMsgHandle hCryptMsg = Interop.Crypt32.CryptMsgOpenToEncode(MsgEncodingType.All, 0, CryptMsgType.CMSG_ENVELOPED, pEnvelopedEncodeInfo, innerContentType.Value, IntPtr.Zero); if (hCryptMsg == null || hCryptMsg.IsInvalid) throw Marshal.GetLastWin32Error().ToCryptographicException(); return hCryptMsg; } } }
private static unsafe void SetCmsRecipientParams(CmsRecipientCollection recipients, X509Certificate2Collection certificates, CryptographicAttributeObjectCollection unprotectedAttributes, AlgorithmIdentifier contentEncryptionAlgorithm, ref CMSG_ENCRYPT_PARAM encryptParam) { checked { recipients = recipients.DeepCopy(); certificates = new X509Certificate2Collection(certificates); 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.CAPISafe.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.CAPISafe.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.CAPISafe.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.CAPISafe.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); } } } }