How to sign a message and verify a message signature (C#)


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

}


</SAMPLE>


 


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)

Comments (1)

  1. hashimsaleem says:

    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