Hi all, welcome back,
Today we'll do some more P/Invoke with CryptoAPI and C#. The following sample is a conversion to C# of the C++ sample in Example C Program: Signing a Message and Verifying a Message Signature:
<SAMPLE file="Class1.cs">
using System; using System.Text; using System.ComponentModel; using System.Runtime.InteropServices; namespace ConsoleApplication1 { class Class1 { [STAThread] static void Main(string[] args) { // Parameters. // String sSignerName = "ALEJANDRO CAMPOS MAGENCIO"; String sMessage = "CryptoAPI is a good way to handle security"; // Variables. // Byte[] pbMessage = null; Int32 cbMessage = 0; IntPtr[] MessageArray = null; Int32[] MessageSizeArray = null; IntPtr hStoreHandle = IntPtr.Zero; IntPtr pSignerCert = IntPtr.Zero; Crypto.CRYPT_SIGN_MESSAGE_PARA SigParams; Boolean res = false; Int32 cbSignedMessageBlob = 0; Byte[] pbSignedMessageBlob = null; Crypto.CRYPT_VERIFY_MESSAGE_PARA VerifyParams; Int32 cbDecodedMessageBlob = 0; Byte[] pbDecodedMessageBlob = null; try { // Begin processing. Display the original message. // Console.WriteLine("-------------------------------------"); Console.WriteLine("MESSAGE TO SIGN:\n"); Console.WriteLine(sMessage + "\n\n"); // Size of message. // pbMessage = (new UnicodeEncoding()).GetBytes(sMessage); cbMessage = pbMessage.Length; // Create the MessageArray and the MessageSizeArray. // MessageArray = new IntPtr[1]; MessageArray[0] = Marshal.AllocHGlobal(pbMessage.Length); Marshal.Copy(pbMessage, 0, MessageArray[0], pbMessage.Length); MessageSizeArray = new Int32[1]; MessageSizeArray[0] = cbMessage; // Open a certificate store. // hStoreHandle = Crypto.CertOpenStore( Crypto.CERT_STORE_PROV_SYSTEM, 0, IntPtr.Zero, Crypto.CERT_SYSTEM_STORE_CURRENT_USER, Crypto.CERT_PERSONAL_STORE_NAME ); if (hStoreHandle == IntPtr.Zero) { throw new Exception("CertOpenStore error", new Win32Exception(Marshal.GetLastWin32Error())); } // Get a pointer to the signer's certificate. // This certificate must have access to the signer's private key. pSignerCert = Crypto.CertFindCertificateInStore( hStoreHandle, Crypto.MY_TYPE, 0, Crypto.CERT_FIND_SUBJECT_STR, sSignerName, IntPtr.Zero ); if (pSignerCert == IntPtr.Zero) { throw new Exception("CertFindCertificateInStore error", new Win32Exception(Marshal.GetLastWin32Error())); } // Initialize the signature structure. // SigParams = new Crypto.CRYPT_SIGN_MESSAGE_PARA(); SigParams.cbSize = Marshal.SizeOf(SigParams); SigParams.dwMsgEncodingType = Crypto.MY_TYPE; SigParams.pSigningCert = pSignerCert; SigParams.HashAlgorithm.pszObjId = Crypto.szOID_OIWSEC_sha1; SigParams.HashAlgorithm.Parameters.pbData = IntPtr.Zero; SigParams.HashAlgorithm.Parameters.cbData = 0; SigParams.pvHashAuxInfo = IntPtr.Zero; SigParams.cMsgCert = 1; GCHandle GC = GCHandle.Alloc(pSignerCert, GCHandleType.Pinned); SigParams.rgpMsgCert = GC.AddrOfPinnedObject(); GC.Free(); SigParams.cMsgCrl = 0; SigParams.rgpMsgCrl = IntPtr.Zero; SigParams.cAuthAttr = 0; SigParams.rgAuthAttr = IntPtr.Zero; SigParams.cUnauthAttr = 0; SigParams.rgUnauthAttr = IntPtr.Zero; SigParams.dwFlags = 0; SigParams.dwInnerContentType = 0; // With two calls to CryptSignMessage, sign the message. // First, get the size of the output signed BLOB. // res = Crypto.CryptSignMessage( ref SigParams, // Signature parameters false, // Not detached 1, // Number of messages MessageArray, // Messages to be signed MessageSizeArray, // Size of messages null, // Buffer for signed message ref cbSignedMessageBlob // Size of buffer ); if (res == false) { throw new Exception("CryptSignMessage error", new Win32Exception(Marshal.GetLastWin32Error())); } // Allocate memory for the signed BLOB. // pbSignedMessageBlob = new Byte[cbSignedMessageBlob]; // Get the SignedMessageBlob. // res = Crypto.CryptSignMessage( ref SigParams, // Signature parameters false, // Not detached 1, // Number of messages MessageArray, // Messages to be signed MessageSizeArray, // Size of messages pbSignedMessageBlob, // Buffer for signed message ref cbSignedMessageBlob // Size of buffer ); if (res == false) { throw new Exception("CryptSignMessage error", new Win32Exception(Marshal.GetLastWin32Error())); } // pbSignedMessageBlob points to the signed BLOB. Display the signature. // Console.WriteLine("-------------------------------------"); Console.WriteLine("SIGNATURE:\n"); Console.WriteLine(Convert.ToBase64String(pbSignedMessageBlob) + "\n\n"); // Verify the message signature. Usually, this // would be done in a separate program. // // Initialize the VerifyParams data structure. // VerifyParams = new Crypto.CRYPT_VERIFY_MESSAGE_PARA(); VerifyParams.cbSize = Marshal.SizeOf(VerifyParams); VerifyParams.dwMsgAndCertEncodingType = Crypto.MY_TYPE; VerifyParams.hCryptProv = IntPtr.Zero; VerifyParams.pfnGetSignerCertificate = IntPtr.Zero; VerifyParams.pvGetArg = IntPtr.Zero; // With two calls to CryptVerifyMessageSignature, verify and decode // the signed message. // First, call CryptVerifyMessageSignature to get the length of the // buffer needed to hold the decoded message. // res = Crypto.CryptVerifyMessageSignature( ref VerifyParams, // Verify parameters. 0, // Signer index. pbSignedMessageBlob, // Pointer to signed BLOB. cbSignedMessageBlob, // Size of signed BLOB. null, // Buffer for decoded message. ref cbDecodedMessageBlob, // Size of buffer. IntPtr.Zero // Pointer to signer certificate. ); if (res == false) { throw new Exception("CryptVerifyMessageSignature error", new Win32Exception(Marshal.GetLastWin32Error())); } // Allocate memory for the buffer. // pbDecodedMessageBlob = new Byte[cbDecodedMessageBlob]; // Call CryptVerifyMessageSignature again to copy the message into // the buffer. // res = Crypto.CryptVerifyMessageSignature( ref VerifyParams, // Verify parameters. 0, // Signer index. pbSignedMessageBlob, // Pointer to signed BLOB. cbSignedMessageBlob, // Size of signed BLOB. pbDecodedMessageBlob, // Buffer for decoded message. ref cbDecodedMessageBlob, // Size of buffer. IntPtr.Zero // Pointer to signer certificate. ); if (res == false) { throw new Exception("CryptVerifyMessageSignature error", new Win32Exception(Marshal.GetLastWin32Error())); } else { // Display attached message to signature. // Console.WriteLine("-------------------------------------"); Console.WriteLine("SIGNATURE VERIFIED!!!\n\n"); Console.WriteLine("-------------------------------------"); Console.WriteLine("ATTACHED MESSAGE:\n"); Console.WriteLine((new UnicodeEncoding()).GetString(pbDecodedMessageBlob) + "\n\n"); } } catch (Exception ex) { // Any errors? Show them. // if (ex.InnerException == null) { Console.WriteLine(ex.Message + "\n\n"); } else { Console.WriteLine(ex.Message + " --> " + ex.InnerException.Message + "\n\n"); } } finally { // Clean up and free memory. // if (MessageArray[0] != IntPtr.Zero) { Marshal.FreeHGlobal(MessageArray[0]); } if (pSignerCert != IntPtr.Zero) { Crypto.CertFreeCertificateContext(pSignerCert); } if (hStoreHandle != IntPtr.Zero) { Crypto.CertCloseStore( hStoreHandle, Crypto.CERT_CLOSE_STORE_CHECK_FLAG ); } } Console.WriteLine("<<Press ENTER to continue>>" + "\n"); Console.ReadLine(); } } }
</SAMPLE>
<SAMPLE file="Crypto.cs">
using System; using System.Runtime.InteropServices; public class Crypto { #region CONSTS // #define CERT_PERSONAL_STORE_NAME L"My" public const string CERT_PERSONAL_STORE_NAME = "My"; // #define CERT_COMPARE_NAME 2 public const Int32 CERT_COMPARE_NAME = 2; // #define CERT_INFO_SUBJECT_FLAG 7 public const Int32 CERT_INFO_SUBJECT_FLAG = 7; // #define CERT_COMPARE_SHIFT 16 public const Int32 CERT_COMPARE_SHIFT = 16; // #define CERT_FIND_SUBJECT_NAME (CERT_COMPARE_NAME << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG) public const Int32 CERT_FIND_SUBJECT_NAME = (CERT_COMPARE_NAME << CERT_COMPARE_SHIFT) | CERT_INFO_SUBJECT_FLAG; // #define CERT_COMPARE_NAME_STR_W 8 public const Int32 CERT_COMPARE_NAME_STR_W = 8; // #define CERT_FIND_SUBJECT_STR_W // (CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG) public const Int32 CERT_FIND_SUBJECT_STR_W = (CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT) | CERT_INFO_SUBJECT_FLAG; // #define CERT_FIND_SUBJECT_STR CERT_FIND_SUBJECT_STR_W public const Int32 CERT_FIND_SUBJECT_STR = CERT_FIND_SUBJECT_STR_W; // #define CERT_STORE_PROV_SYSTEM_W ((LPCSTR) 10) public const Int32 CERT_STORE_PROV_SYSTEM_W = 10; // #define CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W public const Int32 CERT_STORE_PROV_SYSTEM = CERT_STORE_PROV_SYSTEM_W; // #define CERT_SYSTEM_STORE_CURRENT_USER_ID 1 public const Int32 CERT_SYSTEM_STORE_CURRENT_USER_ID = 1; // #define CERT_SYSTEM_STORE_LOCATION_SHIFT 16 public const Int32 CERT_SYSTEM_STORE_LOCATION_SHIFT = 16; // #define CERT_SYSTEM_STORE_CURRENT_USER // (CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) public const Int32 CERT_SYSTEM_STORE_CURRENT_USER = CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT; // #define CERT_CLOSE_STORE_CHECK_FLAG 0x00000002 public const Int32 CERT_CLOSE_STORE_CHECK_FLAG = 0x00000002; // #define ALG_CLASS_HASH (4 << 13) // #define ALG_TYPE_ANY (0) // #define ALG_SID_SHA1 4 // #define CALG_SHA1 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA1) public const Int32 CALG_SHA1 = (4 << 13) | 4; // #define ALG_CLASS_SIGNATURE (1 << 13) // #define ALG_TYPE_RSA (2 << 9) // #define ALG_SID_RSA_ANY 0 // #define CALG_RSA_SIGN (ALG_CLASS_SIGNATURE | ALG_TYPE_RSA | ALG_SID_RSA_ANY) public const Int32 CALG_RSA_SIGN = (1 << 13) | (2 << 9); // #define PROV_RSA_FULL 1 public const Int32 PROV_RSA_FULL = 0x00000001; // #define CRYPT_VERIFYCONTEXT 0xF0000000 public const UInt32 CRYPT_VERIFYCONTEXT = 0xF0000000; //No private key access required // #define X509_ASN_ENCODING 0x00000001 public const Int32 X509_ASN_ENCODING = 0x00000001; // #define PKCS_7_ASN_ENCODING 0x00010000 public const Int32 PKCS_7_ASN_ENCODING = 0x00010000; // #define MY_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) public const Int32 MY_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING; // #define HP_HASHVAL 0x0002 public const Int32 HP_HASHVAL = 0x00000002; // #define HP_HASHSIZE 0x0004 public const Int32 HP_HASHSIZE = 0x00000004; // #define PUBLICKEYBLOBEX 0xA public const Int32 PUBLICKEYBLOBEX = 0x0A; // #define PUBLICKEYBLOB 0x6 public const Int32 PUBLICKEYBLOB = 0x06; // #define CUR_BLOB_VERSION 0x02 public const Int32 CUR_BLOB_VERSION = 0x02; // #define CRYPT_EXPORTABLE 0x00000001 public const Int32 CRYPT_EXPORTABLE = 0x00000001; // #define szOID_RSA_MD5 "1.2.840.113549.2.5" public const String szOID_RSA_MD5 = "1.2.840.113549.2.5"; // #define szOID_RSA_MD5RSA "1.2.840.113549.1.1.4" public const String szOID_RSA_MD5RSA = "1.2.840.113549.1.1.4"; // #define szOID_OIWSEC_sha1 "1.3.14.3.2.26" public const String szOID_OIWSEC_sha1 = "1.3.14.3.2.26"; #endregion #region STRUCTS // typedef struct _PUBLICKEYSTRUC // { // BYTE bType; // BYTE bVersion; // WORD reserved; // ALG_ID aiKeyAlg; // } BLOBHEADER, PUBLICKEYSTRUC; [StructLayout(LayoutKind.Sequential)] public struct PUBLICKEYSTRUC { public Byte bType; public Byte bVersion; public Int16 reserved; public Int32 aiKeyAlg; } // typedef struct _RSAPUBKEY // { // DWORD magic; // DWORD bitlen; // DWORD pubexp; // } RSAPUBKEY; [StructLayout(LayoutKind.Sequential)] public struct RSAPUBKEY { public Int32 magic; public Int32 bitlen; public Int32 pubexp; } // typedef struct _CRYPTOAPI_BLOB // { // DWORD cbData; // BYTE *pbData; // } CRYPT_HASH_BLOB, CRYPT_INTEGER_BLOB, // CRYPT_OBJID_BLOB, CERT_NAME_BLOB; [StructLayout(LayoutKind.Sequential)] public struct CRYPTOAPI_BLOB { public Int32 cbData; public IntPtr pbData; } // typedef struct _CRYPT_ALGORITHM_IDENTIFIER // { // LPSTR pszObjId; // CRYPT_OBJID_BLOB Parameters; // } CRYPT_ALGORITHM_IDENTIFIER; [StructLayout(LayoutKind.Sequential)] public struct CRYPT_ALGORITHM_IDENTIFIER { [MarshalAs(UnmanagedType.LPStr)]public String pszObjId; public CRYPTOAPI_BLOB Parameters; } // typedef struct _CRYPT_SIGN_MESSAGE_PARA // { // DWORD cbSize; // DWORD dwMsgEncodingType; // PCCERT_CONTEXT pSigningCert; // CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm; // void *pvHashAuxInfo; // DWORD cMsgCert; // PCCERT_CONTEXT *rgpMsgCert; // DWORD cMsgCrl; // PCCRL_CONTEXT *rgpMsgCrl; // DWORD cAuthAttr; // PCRYPT_ATTRIBUTE rgAuthAttr; // DWORD cUnauthAttr; // PCRYPT_ATTRIBUTE rgUnauthAttr; // DWORD dwFlags; // DWORD dwInnerContentType; // } CRYPT_SIGN_MESSAGE_PARA; [StructLayout(LayoutKind.Sequential)] public struct CRYPT_SIGN_MESSAGE_PARA { public Int32 cbSize; public Int32 dwMsgEncodingType; public IntPtr pSigningCert; public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm; public IntPtr pvHashAuxInfo; public Int32 cMsgCert; public IntPtr rgpMsgCert; public Int32 cMsgCrl; public IntPtr rgpMsgCrl; public Int32 cAuthAttr; public IntPtr rgAuthAttr; public Int32 cUnauthAttr; public IntPtr rgUnauthAttr; public Int32 dwFlags; public Int32 dwInnerContentType; } // typedef struct _CRYPT_VERIFY_MESSAGE_PARA // { // DWORD cbSize; // DWORD dwMsgAndCertEncodingType; // HCRYPTPROV hCryptProv; // PFN_CRYPT_GET_SIGNER_CERTIFICATE pfnGetSignerCertificate; // void *pvGetArg; // } CRYPT_VERIFY_MESSAGE_PARA; [StructLayout(LayoutKind.Sequential)] public struct CRYPT_VERIFY_MESSAGE_PARA { public Int32 cbSize; public Int32 dwMsgAndCertEncodingType; public IntPtr hCryptProv; public IntPtr pfnGetSignerCertificate; public IntPtr pvGetArg; } #endregion #region FUNCTIONS (IMPORTS) // HCERTSTORE WINAPI CertOpenStore( // LPCSTR lpszStoreProvider, // DWORD dwMsgAndCertEncodingType, // HCRYPTPROV hCryptProv, // DWORD dwFlags, // const void* pvPara // ); [DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern IntPtr CertOpenStore( Int32 lpszStoreProvider, Int32 dwMsgAndCertEncodingType, IntPtr hCryptProv, Int32 dwFlags, String pvPara ); // HCERTSTORE WINAPI CertOpenSystemStore( // HCRYPTPROV hprov, // LPTCSTR szSubsystemProtocol // ); [DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern IntPtr CertOpenSystemStore( IntPtr hprov, String szSubsystemProtocol ); // BOOL WINAPI CertCloseStore( // HCERTSTORE hCertStore, // DWORD dwFlags // ); [DllImport("Crypt32.dll", SetLastError=true)] public static extern Boolean CertCloseStore( IntPtr hCertStore, Int32 dwFlags ); // BOOL WINAPI CryptAcquireContext( // HCRYPTPROV* phProv, // LPCTSTR pszContainer, // LPCTSTR pszProvider, // DWORD dwProvType, // DWORD dwFlags // ); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern bool CryptAcquireContext( ref IntPtr hProv, String pszContainer, String pszProvider, Int32 dwProvType, Int32 dwFlags ); // BOOL WINAPI CryptCreateHash( // HCRYPTPROV hProv, // ALG_ID Algid, // HCRYPTKEY hKey, // DWORD dwFlags, // HCRYPTHASH* phHash // ); [DllImport("advapi32.dll", SetLastError=true)] public static extern bool CryptCreateHash( IntPtr hProv, Int32 Algid, IntPtr hKey, Int32 dwFlags, ref IntPtr phHash ); // BOOL WINAPI CryptGetHashParam( // HCRYPTHASH hHash, // DWORD dwParam, // BYTE* pbData, // DWORD* pdwDataLen, // DWORD dwFlags // ); [DllImport("advapi32.dll", SetLastError=true)] public static extern bool CryptGetHashParam( IntPtr hHash, Int32 dwParam, ref Int32 pbData, ref Int32 pdwDataLen, Int32 dwFlags ); // BOOL WINAPI CryptSetHashParam( // HCRYPTHASH hHash, // DWORD dwParam, // BYTE* pbData, // DWORD dwFlags // ); [DllImport("advapi32.dll", SetLastError=true)] public static extern bool CryptSetHashParam( IntPtr hHash, Int32 dwParam, Byte[] pbData, Int32 dwFlags ); // BOOL WINAPI CryptImportPublicKeyInfo( // HCRYPTPROV hCryptProv, // DWORD dwCertEncodingType, // PCERT_PUBLIC_KEY_INFO pInfo, // HCRYPTKEY* phKey // ); [DllImport("crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern bool CryptImportPublicKeyInfo( IntPtr hCryptProv, Int32 dwCertEncodingType, IntPtr pInfo, ref IntPtr phKey ); // BOOL WINAPI CryptImportKey( // HCRYPTPROV hProv, // BYTE* pbData, // DWORD dwDataLen, // HCRYPTKEY hPubKey, // DWORD dwFlags, // HCRYPTKEY* phKey // ); [DllImport("advapi32.dll", SetLastError=true)] public static extern bool CryptImportKey( IntPtr hProv, Byte[] pbData, Int32 dwDataLen, IntPtr hPubKey, Int32 dwFlags, ref IntPtr phKey ); // BOOL WINAPI CryptVerifySignature( // HCRYPTHASH hHash, // BYTE* pbSignature, // DWORD dwSigLen, // HCRYPTKEY hPubKey, // LPCTSTR sDescription, // DWORD dwFlags // ); [DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern bool CryptVerifySignature( IntPtr hHash, Byte[] pbSignature, Int32 dwSigLen, IntPtr hPubKey, String sDescription, Int32 dwFlags ); // BOOL WINAPI CryptDestroyKey( // HCRYPTKEY hKey // ); [DllImport("advapi32.dll", SetLastError=true)] public static extern bool CryptDestroyKey( IntPtr hKey ); // BOOL WINAPI CryptDestroyHash( // HCRYPTHASH hHash // ); [DllImport("advapi32.dll", SetLastError=true)] public static extern bool CryptDestroyHash( IntPtr hHash ); // BOOL WINAPI CryptReleaseContext( // HCRYPTPROV hProv, // DWORD dwFlags // ); [DllImport("advapi32.dll", SetLastError=true)] public static extern bool CryptReleaseContext( IntPtr hProv, Int32 dwFlags ); // BOOL WINAPI CryptGenKey( // HCRYPTPROV hProv, // ALG_ID Algid, // DWORD dwFlags, // HCRYPTKEY* phKey // ); [DllImport("advapi32.dll", SetLastError=true)] public static extern bool CryptGenKey( IntPtr hProv, Int32 Algid, Int32 dwFlags, ref IntPtr phKey ); // BOOL WINAPI CryptExportKey( // HCRYPTKEY hKey, // HCRYPTKEY hExpKey, // DWORD dwBlobType, // DWORD dwFlags, // BYTE* pbData, // DWORD* pdwDataLen // ); [DllImport("advapi32.dll", SetLastError=true)] public static extern bool CryptExportKey( IntPtr hKey, IntPtr hExpKey, Int32 dwBlobType, Int32 dwFlags, Byte[] pbData, ref Int32 pdwDataLen ); // PCCERT_CONTEXT WINAPI CertFindCertificateInStore( // HCERTSTORE hCertStore, // DWORD dwCertEncodingType, // DWORD dwFindFlags, // DWORD dwFindType, // const void* pvFindPara, // PCCERT_CONTEXT pPrevCertContext // ); [DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern IntPtr CertFindCertificateInStore( IntPtr hCertStore, Int32 dwCertEncodingType, Int32 dwFindFlags, Int32 dwFindType, String pvFindPara, IntPtr pPrevCertContext ); // BOOL WINAPI CertFreeCertificateContext( // PCCERT_CONTEXT pCertContext // ); [DllImport("Crypt32.dll", SetLastError=true)] public static extern Boolean CertFreeCertificateContext( IntPtr pCertContext ); // BOOL WINAPI CryptSignMessage( // PCRYPT_SIGN_MESSAGE_PARA pSignPara, // BOOL fDetachedSignature, // DWORD cToBeSigned, // const BYTE* rgpbToBeSigned[], // DWORD rgcbToBeSigned[], // BYTE* pbSignedBlob, // DWORD* pcbSignedBlob // ); [DllImport("Crypt32.dll", SetLastError=true)] public static extern Boolean CryptSignMessage ( ref CRYPT_SIGN_MESSAGE_PARA pSignPara, Boolean fDetachedSignature, Int32 cToBeSigned, IntPtr[] rgpbToBeSigned, Int32[] rgcbToBeSigned, Byte[] pbSignedBlob, ref Int32 pcbSignedBlob ); // BOOL WINAPI CryptVerifyMessageSignature( // PCRYPT_VERIFY_MESSAGE_PARA pVerifyPara, // DWORD dwSignerIndex, // const BYTE* pbSignedBlob, // DWORD cbSignedBlob, // BYTE* pbDecoded, // DWORD* pcbDecoded, // PCCERT_CONTEXT* ppSignerCert // ); [DllImport("Crypt32.dll", SetLastError=true)] public static extern Boolean CryptVerifyMessageSignature ( ref CRYPT_VERIFY_MESSAGE_PARA pVerifyPara, Int32 dwSignerIndex, Byte[] pbSignedBlob, Int32 cbSignedBlob, Byte[] pbDecoded, ref Int32 pcbDecoded, IntPtr ppSignerCert ); #endregion #region FUNTIONS // Helper function to convert struts & classes to byte array public static byte[] RawSerialize(object anything) { int rawsize = Marshal.SizeOf(anything); IntPtr buffer = Marshal.AllocHGlobal(rawsize); Marshal.StructureToPtr(anything, buffer, false); byte[] rawdatas = new byte[rawsize]; Marshal.Copy(buffer, rawdatas, 0, rawsize); Marshal.FreeHGlobal(buffer); return rawdatas; } #endregion }
Note: I know there are easier ways now in .NET to handle certificate stores (X509Store) and certificates (X509Certificate2), but I decided to include the P/Invoke declarations in case you need them and for illustration purposes.
I hope this helps.
Cheers,
Alex (Alejandro Campos Magencio)
Hi Alex,
Your example has been good so far for me. I am able to successfully produce a PKCS7 message from the code you have posted.
Now, next is that I want to add authenticated attribute to this PKCS7 message. Unfortunately, I found that you have not discussed it in the example. I have written some code to achieve it myself but I am getting access violation on CryptSignMessage API.
I think I am not correctly marshaling the data. Can you help me point it out?
Here is the code which I have written to add authenticated attribute.
//-------------------------------------------------------
// Specify authenticated attributes.
SigParams.cAuthAttr = (uint)_signed_attributes.Count;
SigParams.rgAuthAttr = Marshal.AllocHGlobal(_signed_attributes.Count * Marshal.SizeOf(typeof(NativeWrapper.CRYPT_ATTRIBUTE)));
int j = 0;
foreach (KeyValuePair<string, byte[]> att in _signed_attributes)
{
// Prepare Blob from ByteArray.
NativeWrapper.CRYPTOAPI_BLOB blob = new NativeWrapper.CRYPTOAPI_BLOB();
blob.cbData = (uint)att.Value.Length;
blob.pbData = Marshal.AllocHGlobal(att.Value.Length);
Marshal.Copy(att.Value, 0, blob.pbData, att.Value.Length);
// Prepare CRYPT_ATTRIBUTE structure.
NativeWrapper.CRYPT_ATTRIBUTE authatt = new NativeWrapper.CRYPT_ATTRIBUTE();
authatt.pszObjId = "1.2.840.113583.1.1.8";
authatt.cValue = 1;
authatt.rgValue = Marshal.AllocHGlobal(authatt.cValue * Marshal.SizeOf(typeof(NativeWrapper.CRYPTOAPI_BLOB)));
Marshal.StructureToPtr(blob, authatt.rgValue, false);
// Marshal CRYPT_ATTRIBUTE structure to the SigParams.rgAuthAttr array.
IntPtr pauthatt = new IntPtr(SigParams.rgAuthAttr.ToInt32() +
j * Marshal.SizeOf(typeof (NativeWrapper.CRYPT_ATTRIBUTE)));
Marshal.StructureToPtr(authatt, pauthatt, false);
++j;
}
Thanks and Regards