Retired Microsoft Blog disclaimer

This directory is a mirror of retired "Decrypt My World" MSDN blog and is provided as is. All posting authorship and copyrights belong to respective authors.

Posts on this page:

Original URL: https://blogs.msdn.microsoft.com/alejacma/2008/03/06/capicom-support-on-windows-server-2008/
Post name: CAPICOM support on Windows Server 2008
Original author: Alejandro Campos Magencio
Posting date: 2008-03-06T01:52:00+00:00


Hi all, welcome back,

If you remember all the confusion there was regarding CAPICOM support on Vista, now everything seems much clearer on Windows Server 2008. Our documentation team has done its homework, as we can see in CAPICOM Reference:

"CAPICOM is available for use in the following operating systems: Windows Server 2008, Windows Vista, Windows XP, and Windows 2000. It may be altered or unavailable in subsequent versions. Instead, use the .NET Framework to implement security features."

I hope this helps.

Cheers,

Alex (Alejandro Campos Magencio)


Original URL: https://blogs.msdn.microsoft.com/alejacma/2008/03/06/pkcs11-interface-support-on-windows-2000server-2003/
Post name: PKCS#11 interface support on Windows 2000/Server 2003
Original author: Alejandro Campos Magencio
Posting date: 2008-03-06T01:07:00+00:00


Hi all, welcome back,

I recently had some issues involving PKCS#11 interface on Windows,and it seems quite clear that we don't support it, at least on Windows 2000 &Server 2003, and as far as I know on any other version of Windows:

Public Key Interoperability
"
Hardware Support
...
Windows 2000 uses CryptoAPI to abstract hardware-based key management from applications and uses the PC/SC standard instead of PKCS#11 to communicate with smart cards and readers. Entrust, Netscape and Baltimore have their own cryptographic APIs and use PKCS#11 to interface to hardware tokens like smart cards. IBM uses CDSA as its cryptographic framework that includes support for hardware devices. Because Windows 2000 requires hardware devices to also support Plug and Play and Power Management features, and Microsoft's implementation of PC/SC includes support for these ease-of-use features, there are no plans to add support for PKCS#11 in Windows 2000.
"

Evaluating Factors That Affect Extended Trusts
"
Algorithm Support
...
Windows Server 2003 uses CryptoAPI to abstract hardware-based key management from applications, and it uses the PC/SC standard instead of PKCS#11 to communicate with smart cards and readers. Many third-party CAs have their own cryptographic APIs and use PKCS#11 to interface to hardware tokens such as smart cards. Because Windows 2000 and Windows Server 2003 require hardware devices to support Plug and Play and power management features, and PC/SC includes support for these ease-of-use features, Windows Server 2003 does not support PKCS#11.
Note
• The Windows Server 2003 PKI can use third-party CSPs, and can enroll users for certificates that have keys that were generated by third-party CSPs.
"

So if you have any issues with a PKCS#11 interface, Microsoft Technical Supportis not the one you should contact, but the provider of the interface instead.

I hope this helps.

Cheers,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2008/03/04/how-to-get-the-logged-on-user-with-wmi-vbscript/
Post name: How to get the logged on user with WMI (VBScript)
Original author: Alejandro Campos Magencio
Posting date: 2008-03-04T07:06:00+00:00


Hi all, welcome back,


From time to time I get to do some scripting, play with LDAP/ADSI, WMI, etc. I'll begin posting some VBScript samples I have which may be useful for you too.


Today we'll see a way to get the user who has logged on a given machine with VBScript & WMI:


' PARAMETERS
'
strComputer = "machineName" ' use "." for local computer
strUser = "domain\user" ' comment this line for current user
strPassword = "password" ' comment this line for current user

' CONSTANTS
'
wbemImpersonationLevelImpersonate = 3
wbemAuthenticationLevelPktPrivacy = 6

'=======================================================================
' MAIN
'=======================================================================

' Connect to machine
'
If Not strUser = "" Then

' Connect using user and password
'
Set objLocator = CreateObject("WbemScripting.SWbemLocator")
Set objWMI = objLocator.ConnectServer _
(strComputer, "root\cimv2", strUser, strPassword)
objWMI.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate
objWMI.Security_.AuthenticationLevel = wbemAuthenticationLevelPktPrivacy

Else

' Connect using current user
'
Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

End If

' Get OS name
'
Set colOS = objWMI.InstancesOf ("Win32_OperatingSystem")

For Each objOS in colOS
strName = objOS.Name
Next

If Instr(strName, "Windows 2000") > 0 Then

'-------------------------------------------------------------------
' Code for Windows 2000
'-------------------------------------------------------------------

' Get user name
'
Set colComputer = objWMI.ExecQuery("Select * from Win32_ComputerSystem")

For Each objComputer in colComputer
Wscript.Echo "User: " & objComputer.UserName
Next

' ------------------------------------------------------------------

Else

' ------------------------------------------------------------------
' Code for Windows XP or later
' ------------------------------------------------------------------

' Get interactive session
'
Set colSessions = objWMI.ExecQuery _
("Select * from Win32_LogonSession Where LogonType = 2")

If colSessions.Count = 0 Then
' No interactive session found
'
Wscript.Echo "No interactive user found"
Else
'Interactive session found
'
For Each objSession in colSessions

Set colList = objWMI.ExecQuery("Associators of " _
& "{Win32_LogonSession.LogonId=" & objSession.LogonId & "} " _
& "Where AssocClass=Win32_LoggedOnUser Role=Dependent" )

' Show user info
'
For Each objItem in colList
WScript.Echo "User: " & objItem.Name
WScript.Echo "FullName: " & objItem.FullName
WScript.Echo "Domain: " & objItem.Domain
Next

' Show session start time
'
Wscript.Echo "Start Time: " & objSession.StartTime
Next
End If

' ------------------------------------------------------------------

End If

'=======================================================================



I hope this helps.


Cheers,



Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2008/03/03/how-to-select-which-smart-card-reader-to-perform-actions-on/
Post name: How to select which Smart Card reader to perform actions on
Original author: Alejandro Campos Magencio
Posting date: 2008-03-03T06:40:00+00:00


Hi all, welcome back,

Most of the time we only have a smart card reader in our machine, and we only use one smart card to perform crypto operations. But what if we have several readers and cards, and those cards share the same CSP (Cryptographic Service Provider)? Can we select the one we want to use when working with CryptoAPI/XEnroll/CertEnroll?

Let's take a look to XEnroll, for instance: We can set WriteCertToCSP Property of the ICEnroll4 Interface to TRUE so the certificates will be written to the smart card in addition to being written to "MY" store when calling i.e. acceptPKCS7 method (Note: WriteCertToCSP is TRUE by default). But apparently we can't specify which card we want to write the cert to. So what happens if we have two cards with same CSP inserted at the same time? Well, in this case the CSP itself will be responsible of giving the user the possibility to choose the card it wants. When we enroll the cert, the CSP should show a dialog so we can choosethe appropiatecard.

As you sure know, XEnroll won’t work on Vista. Vista now uses the new certificate enrollment component CertEnroll (see Certificate Enrollment API for more info). But my comments still apply here: the CSP should help us to choose the card.

And what if we want to do the selection programmatically? Can that be done? Yes, we may be able to do it. If we want to select the card for the CSP then we should figure out which reader the card is in, and then use the "\\.\<Reader Name>\" format for the container name when calling CryptAcquireContext API, for instance. If we also know the container name we can use "\\.\<Reader Name>\<Container Name>\" (See the smart card white paper for more details on our MS Base CSP). The CSP should be able to work with the right card.

I hope this helps.
Cheers,

Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2008/02/21/how-to-sign-a-message-and-verify-a-message-signature-c/
Post name: How to sign a message and verify a message signature (C#)
Original author: Alejandro Campos Magencio
Posting date: 2008-02-21T12:10:00+00:00


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)