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/2007/12/11/xmldsigc14ntransform-normalization-behavior-depends-on-input-type/
Post name: XmlDsigC14NTransform normalization behavior depends on input type
Original author: Alejandro Campos Magencio
Posting date: 2007-12-11T08:51:00+00:00


Hi, welcome back,


When using System.Security.Cryptography.Xml.XmlDsigC14NTransform, depending on the input type (XmlDsigC14NTransform.InputTypes) being passed to itsLoadInput method, the result of its GetOutput method could be different:



- If we pass a Stream to XmlDsigC14NTransform, it will normalize line feeds from 0xd 0xa ("\r\n") to 0xa ("\n") before canonicalization. After canonicalization, we will only see 0xa chars ("\n") in the Output as expected.



- If we pass an XmlNodeList or XmlDocument to XmlDsigC14NTransform, line feeds won't be normalized before canonicalization. After canonicalization, 0xd 0xa ("\r\n") will appear in the Output as 0x26 0x0b 0x78 0x44 0x3b 0x0a ("
\n"). Canonicalization will convert all 0xd bytes to "
" string as documented in C14N standard.



The following sample converts an XmlNodeList to a Stream, so we can get the same behaviorthan with a Stream:



<SAMPLE>

XmlNodeList xmlNodes = ...

// Convert XmlNodeList to Stream, so XmlDsigC14NTransform is able to normalize input
MemoryStream memStream = new MemoryStream();
byte[] bytes = new UTF8Encoding().GetBytes(xmlNodes[0].OuterXml);
memStream.Write(bytes, 0, bytes.Length);
memStream.Seek(0, SeekOrigin.Begin);

// Normalize & Canonicalize
XmlDsigC14NTransform t2 = new XmlDsigC14NTransform();
t2.LoadInput(memStream);


</SAMPLE>



I hope this helps.


Cheers,



Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2007/12/03/rsacryptoserviceprovider-fails-when-used-with-asp-net/
Post name: RSACryptoServiceProvider fails when used with ASP.NET
Original author: Alejandro Campos Magencio
Posting date: 2007-12-03T04:00:00+00:00


Hi, welcome back,


I will talk today about a very common issue we face when we try to use .NET's RSACryptoServiceProvider class in ASP.NET.


When we try to create a new RSACryptoServiceProvider object in this scenario, we mayget the following exception:


"System.Security.Cryptography.CryptographicException: The system cannot find the file specified".



By using my CryptoAPI Tracer scriptwe can take a look to the CryptoAPI calls that .NET is making behind the scenes. Thanks to this script we will be able to see the exact API that is failing and the exact error (which most of the time .NET masks).


In our case, the API that fails is CryptAcquireContext, and it fails with error #2(ERROR_FILE_NOT_FOUND). According to CryptAcquireContext documentation, this error means the following:
"
The profile of the user is not loaded and cannot be found. This happens when the application impersonates a user, for example, the IUSR_ComputerName account.
"


By default, ASP.NET won't load the user profile. Take a look to the parameters of the problematicCryptAcquireContext call as being shown in the log file that my script generated. If this API is not being called with CRYPT_MACHINE_KEYSET (to use the machine profile) or CRYPT_VERIFYCONTEXT (to use temporary key stores), it will try to access the key stores in the user profile, and it will fail because its not loaded.


Which options do we have here then?


1) If we need each user running your ASP.NET app to use their own key stores, we will have to load their user profile. We can do it with LoadUserProfile API. The only problem is that the privileges needed to execute this API are quite powerful for a standard user.


2) If we still need the user profile and don't want to give users enough privileges to run LoadUserProfile, there is a trick we can use: Service Control Manager (SCM) will automatically load the profile of the user that a Windows service uses to run. So we may create a dummy Windows service which runs with our user's credentials. This service won't need to do anything special, just stay alive. SCM will load the user profile for us and ASP.NET will be able to use it automatically once it gets loaded.


3)We may also use machine key stores instead of user's. We just have to pass CRYPT_MACHINE_KEYSET flag to CryptAcquireContext. In order to do that in .NET, we may use a code like this:

CspParameters RSAParams = new CspParameters();
RSAParams.Flags = CspProviderFlags.UseMachineKeyStore;
RSACryptoServiceProvider sp = new RSACryptoServiceProvider(1024, RSAParams);

Note. When we use machine key stores, any user in that machine may have access to those keys.



I hope this helps.


Cheers,



Alex(Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2007/11/26/pinvoking-cryptoapi-in-net-vb-net-version/
Post name: P/Invoking CryptoAPI in .NET (VB.NET version)
Original author: Alejandro Campos Magencio
Posting date: 2007-11-26T06:01:00+00:00


Hi, welcome back,


This is a continuation of my previous post, P/Invoking CryptoAPI in .NET (C# version).


Here you have themost common P/Invoke CryptoAPI declarations I've successfully used in the past, but this time for VB.NET (Note: I've included a coupleof auxiliary functions which maybe of help, too.CertContextFromCertSubject getsa certificate context from a certificate inMY/Personal certificate store, andRSACryptoServiceProviderFromCertContext creates an RSACryptoServiceProvider object from that certificate context. I don't have them in C#, but they should be easy to convert):



<SAMPLE>

Imports System.Runtime.InteropServices
Imports System.Security.Cryptography
Imports System.ComponentModel

Public Class Crypto

#Region "CONSTS"

' #define BUFSIZE 1024
Public Const BUFSIZE As Int32 = 1024

' #define AT_KEYEXCHANGE 1
Public Const AT_KEYEXCHANGE As Int32 = 1

' #define AT_SIGNATURE 2
Public Const AT_SIGNATURE As Int32 = 2

' #define CERT_STORE_PROV_SYSTEM_W ((LPCSTR) 10)
Public Const CERT_STORE_PROV_SYSTEM_W As Int32 = 10

' #define CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W
Public Const CERT_STORE_PROV_SYSTEM As Int32 = CERT_STORE_PROV_SYSTEM_W

' #define CERT_SYSTEM_STORE_CURRENT_USER_ID 1
Public Const CERT_SYSTEM_STORE_CURRENT_USER_ID As Int32 = 1

' #define CERT_SYSTEM_STORE_LOCATION_SHIFT 16
Public Const CERT_SYSTEM_STORE_LOCATION_SHIFT As Int32 = 16

' #define CERT_SYSTEM_STORE_CURRENT_USER \
' (CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT)
Public Const CERT_SYSTEM_STORE_CURRENT_USER As Int32 = _
CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT

' #define CERT_PERSONAL_STORE_NAME L"My"
Public Const CERT_PERSONAL_STORE_NAME As String = "My"

' #define X509_ASN_ENCODING 0x00000001
Public Const X509_ASN_ENCODING As Int32 = &H1

' #define PKCS_7_ASN_ENCODING 0x00010000
Public Const PKCS_7_ASN_ENCODING As Int32 = &H10000

' #define MY_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
Public Const MY_TYPE As Int32 = PKCS_7_ASN_ENCODING + X509_ASN_ENCODING

' #define CERT_COMPARE_ANY 0
Public Const CERT_COMPARE_ANY As Int32 = 0

' #define CERT_COMPARE_SHA1_HASH 1
Public Const CERT_COMPARE_SHA1_HASH As Int32 = 1

' #define CERT_COMPARE_SHIFT 16
Public Const CERT_COMPARE_SHIFT As Int32 = 16

' #define CERT_FIND_SHA1_HASH (CERT_COMPARE_SHA1_HASH << CERT_COMPARE_SHIFT)
Public Const CERT_FIND_SHA1_HASH As Int32 = CERT_COMPARE_SHA1_HASH << CERT_COMPARE_SHIFT

' #define CERT_FIND_HASH CERT_FIND_SHA1_HASH
Public Const CERT_FIND_HASH As Int32 = CERT_FIND_SHA1_HASH

' #define CERT_FIND_ANY (CERT_COMPARE_ANY << CERT_COMPARE_SHIFT)
Public Const CERT_FIND_ANY As Int32 = CERT_COMPARE_ANY << CERT_COMPARE_SHIFT

' #define CERT_COMPARE_NAME 2
Public Const CERT_COMPARE_NAME As Int32 = 2

' #define CERT_INFO_SUBJECT_FLAG 7
Public Const CERT_INFO_SUBJECT_FLAG As Int32 = 7

' #define CERT_FIND_SUBJECT_NAME (CERT_COMPARE_NAME << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG)
Public Const CERT_FIND_SUBJECT_NAME As Int32 = (CERT_COMPARE_NAME << CERT_COMPARE_SHIFT) + CERT_INFO_SUBJECT_FLAG

' #define CERT_COMPARE_NAME_STR_W 8
Public Const CERT_COMPARE_NAME_STR_W As Int32 = 8

' #define CERT_FIND_SUBJECT_STR_W \
' (CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG)
Public Const CERT_FIND_SUBJECT_STR_W As Int32 = (CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT) + CERT_INFO_SUBJECT_FLAG

' #define CERT_FIND_SUBJECT_STR CERT_FIND_SUBJECT_STR_W
Public Const CERT_FIND_SUBJECT_STR As Int32 = CERT_FIND_SUBJECT_STR_W

' #define CERT_CLOSE_STORE_CHECK_FLAG 0x00000002
Public Const CERT_CLOSE_STORE_CHECK_FLAG As Int32 = &H2

' #define ALG_CLASS_HASH (4 << 13)
Public Const ALG_CLASS_HASH As Int32 = 4 << 13

' #define ALG_TYPE_ANY (0)
Public Const ALG_TYPE_ANY As Int32 = 0

' #define ALG_SID_MD5 3
Public Const ALG_SID_MD5 As Int32 = 3

' #define ALG_SID_SHA1 4
Public Const ALG_SID_SHA1 As Int32 = 4

' #define CALG_MD5 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5)
Public Const CALG_MD5 As Int32 = ALG_CLASS_HASH + ALG_TYPE_ANY + ALG_SID_MD5

' #define CALG_SHA1 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA1)
Public Const CALG_SHA1 As Int32 = ALG_CLASS_HASH + ALG_TYPE_ANY + ALG_SID_SHA1

' #define PP_KEYEXCHANGE_PIN 32
Public Const PP_KEYEXCHANGE_PIN As Int32 = 32

' #define PP_SIGNATURE_PIN 33
Public Const PP_SIGNATURE_PIN As Int32 = 33

' #define PROV_RSA_FULL 1
Public Const PROV_RSA_FULL As Int32 = &H1

' #define CRYPT_VERIFYCONTEXT 0xF0000000
Public Const CRYPT_VERIFYCONTEXT As Int32 = &HF0000000

' #define CERT_KEY_PROV_INFO_PROP_ID 2
Public Const CERT_KEY_PROV_INFO_PROP_ID As Int32 = 2

#End Region

#Region "STRUCTS"

' typedef struct _CRYPTOAPI_BLOB {
' DWORD cbData;
' BYTE *pbData;
' } CRYPT_HASH_BLOB, CRYPT_INTEGER_BLOB,
' CRYPT_OBJID_BLOB, CERT_NAME_BLOB;
<StructLayout(LayoutKind.Sequential)> _
Public Structure CRYPTOAPI_BLOB
Public cbData As Int32
Public pbData As IntPtr
End Structure

' typedef struct _CRYPT_ALGORITHM_IDENTIFIER {
' LPSTR pszObjId;
' CRYPT_OBJID_BLOB Parameters;
' } CRYPT_ALGORITHM_IDENTIFIER;
<StructLayout(LayoutKind.Sequential)> _
Public Structure CRYPT_ALGORITHM_IDENTIFIER
<MarshalAs(UnmanagedType.LPStr)> Public pszObjId As String
Public Parameters As CRYPTOAPI_BLOB
End Structure

' typedef struct _FILETIME {
' DWORD dwLowDateTime;
' DWORD dwHighDateTime;
' } FILETIME;
<StructLayout(LayoutKind.Sequential)> _
Public Structure FILETIME
Public dwLowDateTime As Int32
Public dwHighDateTime As Int32
End Structure

' typedef struct _CRYPT_BIT_BLOB {
' DWORD cbData;
' BYTE *pbData;
' DWORD cUnusedBits;
' } CRYPT_BIT_BLOB;
<StructLayout(LayoutKind.Sequential)> _
Public Structure CRYPT_BIT_BLOB
Public cbData As Int32
Public pbData As Byte()
Public cUnusedBits As Int32
End Structure

' typedef struct _CERT_PUBLIC_KEY_INFO {
' CRYPT_ALGORITHM_IDENTIFIER Algorithm;
' CRYPT_BIT_BLOB PublicKey;
' } CERT_PUBLIC_KEY_INFO;
<StructLayout(LayoutKind.Sequential)> _
Public Structure CERT_PUBLIC_KEY_INFO
Public Algorithm As CRYPT_ALGORITHM_IDENTIFIER
Public PublicKey As CRYPT_BIT_BLOB
End Structure

' typedef struct _CERT_INFO {
' DWORD dwVersion;
' CRYPT_INTEGER_BLOB SerialNumber;
' CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
' CERT_NAME_BLOB Issuer;
' FILETIME NotBefore;
' FILETIME NotAfter;
' CERT_NAME_BLOB Subject;
' CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo;
' CRYPT_BIT_BLOB IssuerUniqueId;
' CRYPT_BIT_BLOB SubjectUniqueId;
' DWORD cExtension;
' PCERT_EXTENSION rgExtension;
' } CERT_INFO;
<StructLayout(LayoutKind.Sequential)> _
Public Structure CERT_INFO
Public dwVersion As Int32
Public SerialNumber As CRYPTOAPI_BLOB
Public SignatureAlgorithm As CRYPT_ALGORITHM_IDENTIFIER
Public Issuer As CRYPTOAPI_BLOB
Public NotBefore As FILETIME
Public NotAfter As FILETIME
Public Subject As CRYPTOAPI_BLOB
Public SubjectPublicKeyInfo As CERT_PUBLIC_KEY_INFO
Public IssuerUniqueId As CRYPT_BIT_BLOB
Public SubjectUniqueId As CRYPT_BIT_BLOB
Public cExtension As Int32
Public rgExtension As IntPtr
End Structure

' typedef struct _CERT_CONTEXT {
' DWORD dwCertEncodingType;
' BYTE *pbCertEncoded;
' DWORD cbCertEncoded;
' PCERT_INFO pCertInfo;
' HCERTSTORE hCertStore;
' } CERT_CONTEXT;
<StructLayout(LayoutKind.Sequential)> _
Public Structure CERT_CONTEXT
Public dwCertEncodingType As Int32
Public pbCertEncoded As Byte()
Public cbCertEncoded As Int32
Public pCertInfo As IntPtr
Public hCertStore As IntPtr
End Structure

#End Region

#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 Shared Function CertOpenStore( _
ByVal lpszStoreProvider As Int32, _
ByVal dwMsgAndCertEncodingType As Int32, _
ByVal hCryptProv As IntPtr, _
ByVal dwFlags As Int32, _
ByVal pvPara As String _
) As IntPtr
End Function

' HCERTSTORE WINAPI CertOpenSystemStore(
' HCRYPTPROV hprov,
' LPTCSTR szSubsystemProtocol
');
<DllImport("Crypt32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Public Shared Function CertOpenSystemStore( _
ByVal hprov As IntPtr, _
ByVal szSubsystemProtocol As String _
) As IntPtr
End Function

' PCCERT_CONTEXT WINAPI CertFindCertificateInStore(
' HCERTSTORE hCertStore,
' DWORD dwCertEncodingType,
' DWORD dwFindFlags,
' DWORD dwFindType,
' const void* pvFindPara,
' PCCERT_CONTEXT pPrevCertContext
' );
'<DllImport("Crypt32.dll", SetLastError:=True)> _
'Public Shared Function CertFindCertificateInStore( _
' ByVal hCertStore As IntPtr, _
' ByVal dwCertEncodingType As Int32, _
' ByVal dwFindFlags As Int32, _
' ByVal dwFindType As Int32, _
' ByRef pvFindPara As CRYPTOAPI_BLOB, _
' ByVal pPrevCertContext As IntPtr _
') As IntPtr
'End Function
<DllImport("Crypt32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Public Shared Function CertFindCertificateInStore( _
ByVal hCertStore As IntPtr, _
ByVal dwCertEncodingType As Int32, _
ByVal dwFindFlags As Int32, _
ByVal dwFindType As Int32, _
ByVal pvFindPara As String, _
ByVal pPrevCertContext As IntPtr _
) As IntPtr
End Function

' BOOL WINAPI CryptAcquireCertificatePrivateKey(
' PCCERT_CONTEXT pCert,
' DWORD dwFlags,
' void* pvReserved,
' HCRYPTPROV* phCryptProv,
' DWORD* pdwKeySpec,
' BOOL* pfCallerFreeProv
' );
<DllImport("Crypt32.dll", SetLastError:=True)> _
Public Shared Function CryptAcquireCertificatePrivateKey( _
ByVal pCert As IntPtr, _
ByVal dwFlags As Int32, _
ByVal pvReserverd As IntPtr, _
ByRef phCryptProv As IntPtr, _
ByRef pdwKeySpec As Int32, _
ByRef pfCallerFreeProv As Boolean _
) As Boolean
End Function

' BOOL WINAPI CertCloseStore(
' HCERTSTORE hCertStore,
' DWORD dwFlags
' );
<DllImport("Crypt32.dll", SetLastError:=True)> _
Public Shared Function CertCloseStore( _
ByVal hCertStore As IntPtr, _
ByVal dwFlags As Int32 _
) As Boolean
End Function

' BOOL WINAPI CryptReleaseContext(
' HCRYPTPROV hProv,
' DWORD dwFlags
' );
<DllImport("Advapi32.dll", SetLastError:=True)> _
Public Shared Function CryptReleaseContext( _
ByVal hProv As IntPtr, _
ByVal dwFlags As Int32 _
) As Boolean
End Function

' BOOL WINAPI CryptCreateHash(
' HCRYPTPROV hProv,
' ALG_ID Algid,
' HCRYPTKEY hKey,
' DWORD dwFlags,
' HCRYPTHASH* phHash
' );
<DllImport("advapi32.dll", SetLastError:=True)> _
Public Shared Function CryptCreateHash( _
ByVal hProv As IntPtr, _
ByVal Algid As Int32, _
ByVal hKey As IntPtr, _
ByVal dwFlags As Int32, _
ByRef phHash As IntPtr _
) As Boolean
End Function

' BOOL WINAPI CryptDestroyHash(
' HCRYPTHASH hHash
' );
<DllImport("advapi32.dll", SetLastError:=True)> _
Public Shared Function CryptDestroyHash( _
ByVal hHash As IntPtr _
) As Boolean
End Function

' BOOL WINAPI CryptSetProvParam(
' HCRYPTPROV hProv,
' DWORD dwParam,
' BYTE* pbData,
' DWORD dwFlags
' );
<DllImport("advapi32.dll", SetLastError:=True)> _
Public Shared Function CryptSetProvParam( _
ByVal hProv As IntPtr, _
ByVal dwParam As Int32, _
ByVal pbData As Byte(), _
ByVal dwFlags As Int32 _
) As Boolean
End Function

' BOOL WINAPI CryptHashData(
' HCRYPTHASH hHash,
' BYTE* pbData,
' DWORD dwDataLen,
' DWORD dwFlags
' );
<DllImport("advapi32.dll", SetLastError:=True)> _
Public Shared Function CryptHashData( _
ByVal hHash As IntPtr, _
ByVal pbData As Byte(), _
ByVal dwDataLen As Int32, _
ByVal dwFlags As Int32 _
) As Boolean
End Function

' BOOL WINAPI CryptSignHash(
' HCRYPTHASH hHash,
' DWORD dwKeySpec,
' LPCTSTR sDescription,
' DWORD dwFlags,
' BYTE* pbSignature,
' DWORD* pdwSigLen
' );
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Public Shared Function CryptSignHash( _
ByVal hHash As IntPtr, _
ByVal dwKeySpec As Int32, _
ByVal sDescription As String, _
ByVal dwFlags As Int32, _
ByVal pbSignature As Byte(), _
ByRef pdwSigLen As Int32 _
) As Boolean
End Function

' BOOL WINAPI CertFreeCertificateContext(
' PCCERT_CONTEXT pCertContext
' );
<DllImport("Crypt32.dll", SetLastError:=True)> _
Public Shared Function CertFreeCertificateContext( _
ByVal pCertContext As IntPtr _
) As Boolean
End Function

' BOOL WINAPI CryptAcquireContext(
' HCRYPTPROV* phProv,
' LPCTSTR pszContainer,
' LPCTSTR pszProvider,
' DWORD dwProvType,
' DWORD dwFlags
' );
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Public Shared Function CryptAcquireContext( _
ByRef hProv As IntPtr, _
ByVal pszContainer As String, _
ByVal pszProvider As String, _
ByVal dwProvType As Int32, _
ByVal dwFlags As Int32 _
) As Boolean
End Function

' BOOL WINAPI CryptImportPublicKeyInfo(
' HCRYPTPROV hCryptProv,
' DWORD dwCertEncodingType,
' PCERT_PUBLIC_KEY_INFO pInfo,
' HCRYPTKEY* phKey
' );
<DllImport("crypt32.dll", SetLastError:=True)> _
Public Shared Function CryptImportPublicKeyInfo( _
ByVal hCryptProv As IntPtr, _
ByVal dwCertEncodingType As Int32, _
ByVal pInfo As IntPtr, _
ByRef phKey As IntPtr _
) As Boolean
End Function

' BOOL WINAPI CryptVerifySignature(
' HCRYPTHASH hHash,
' BYTE* pbSignature,
' DWORD dwSigLen,
' HCRYPTKEY hPubKey,
' LPCTSTR sDescription,
' DWORD dwFlags
' );
<DllImport("advapi32.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
Public Shared Function CryptVerifySignature( _
ByVal hHash As IntPtr, _
ByVal pbSignature As Byte(), _
ByVal dwSigLen As Int32, _
ByVal hPubKey As IntPtr, _
ByVal sDescription As String, _
ByVal dwFlags As Int32 _
) As Boolean
End Function

' BOOL WINAPI CryptDestroyKey(
' HCRYPTKEY hKey
' );
<DllImport("advapi32.dll", SetLastError:=True)> _
Public Shared Function CryptDestroyKey( _
ByVal hKey As IntPtr _
) As Boolean
End Function

' BOOL WINAPI CertGetCertificateContextProperty(
' PCCERT_CONTEXT pCertContext,
' DWORD dwPropId,
' void* pvData,
' DWORD* pcbData
' );
<DllImport("crypt32.dll", SetLastError:=True)> _
Public Shared Function CertGetCertificateContextProperty( _
ByVal pCertContext As IntPtr, _
ByVal dwPropId As Int32, _
ByVal pvData As IntPtr, _
ByRef pcbData As Int32 _
) As Boolean
End Function

' PCCERT_CONTEXT WINAPI CertEnumCertificatesInStore(
' HCERTSTORE hCertStore,
' PCCERT_CONTEXT pPrevCertContext
');
<DllImport("crypt32.dll", SetLastError:=True)> _
Public Shared Function CertEnumCertificatesInStore( _
ByVal hCertStore As IntPtr, _
ByVal pPrevCertContext As IntPtr _
) As IntPtr
End Function

' PCCERT_CONTEXT WINAPI CertDuplicateCertificateContext(
' PCCERT_CONTEXT pCertContext
');
<DllImport("crypt32.dll", SetLastError:=True)> _
Public Shared Function CertDuplicateCertificateContext( _
ByVal pCertContext As IntPtr _
) As IntPtr
End Function

#End Region

#Region "FUNCTIONS"

Public Shared Function CertContextFromCertSubject(ByVal subject As String) As IntPtr

' Variables
'
Dim bResult As Boolean = False
Dim hStoreHandle As IntPtr = IntPtr.Zero
Dim pCertContext As IntPtr = IntPtr.Zero

Try

' Open the certificate store.
'
hStoreHandle = CertOpenSystemStore( _
0, _
CERT_PERSONAL_STORE_NAME _
)
If (hStoreHandle.Equals(IntPtr.Zero)) Then
Throw New Exception("CertOpenStore error", New Win32Exception(Marshal.GetLastWin32Error()))
End If

' Get a certificate that matches the search criteria.
'
pCertContext = CertFindCertificateInStore( _
hStoreHandle, _
MY_TYPE, _
0, _
CERT_FIND_SUBJECT_STR, _
subject, _
IntPtr.Zero _
)
If (pCertContext.Equals(IntPtr.Zero)) Then
Throw New Exception("CertFindCertificateInStore error", New Win32Exception(Marshal.GetLastWin32Error()))
End If

Return pCertContext

Catch ex As Exception

' Any errors? Show them.
'
If (ex.InnerException Is Nothing) Then
MessageBox.Show(ex.Message)
Else
MessageBox.Show(ex.Message + " --> " + ex.InnerException.Message)
End If

Finally

' Clean up and free memory.
'
If (Not hStoreHandle.Equals(IntPtr.Zero)) Then
bResult = CertCloseStore( _
hStoreHandle, _
CERT_CLOSE_STORE_CHECK_FLAG _
)
End If

End Try

Return Nothing

End Function

' Converted to VB.NET from KB article 320602
'
Public Shared Function RSACryptoServiceProviderFromCertContext(ByVal pCertContext As IntPtr) As RSACryptoServiceProvider

'Determine the size of the buffer that you need to allocate.
'
Dim cbData As Int32 = 0
Dim fStatus As Boolean = CertGetCertificateContextProperty( _
pCertContext, _
CERT_KEY_PROV_INFO_PROP_ID, _
0, _
cbData)

If (Not fStatus) Then
MessageBox.Show("CertGetCertificateContextProperty error --> " + Marshal.GetLastWin32Error().ToString())

' Get the CERT_KEY_PROV_HANDLE_PROP_ID value and the HCRYPTPROV value.
'
cbData = 4
Dim pCryptKeyProvInfo As IntPtr = Marshal.AllocHGlobal(New IntPtr(cbData))
fStatus = CertGetCertificateContextProperty( _
pCertContext, _
CERT_KEY_PROV_INFO_PROP_ID, _
pCryptKeyProvInfo, _
cbData)

If (Not fStatus) Then
MessageBox.Show("CertGetCertificateContextProperty error --> " + Marshal.GetLastWin32Error().ToString())
End If
Return Nothing

End If

If (Not cbData = 0) Then

' Allocate an unmanaged buffer to store the CRYPT_KEY_PROV_INFO structure.
'
Dim pCryptKeyProvInfo As IntPtr = Marshal.AllocHGlobal(cbData)

' Get the CRYPT_KEY_PROV_INFO structure.
'
fStatus = CertGetCertificateContextProperty( _
pCertContext, _
CERT_KEY_PROV_INFO_PROP_ID, _
pCryptKeyProvInfo, _
cbData)

If (Not fStatus) Then
MessageBox.Show("CertGetCertificateContextProperty failed: " + Marshal.GetLastWin32Error().ToString())
Marshal.FreeHGlobal(pCryptKeyProvInfo)
Else

' Build a CspParameters object with the provider type, the provider name,
' and the container name from the CRYPT_KEY_PROV_INFO structure.
' The pointer to the container name is the first DWORD in the CRYPT_KEY_PROV_INFO
' structure, the pointer to the provider name is the second DWORD, and
' the provider type is the third DWORD.
'
Try
Dim CspParams As CspParameters = New CspParameters( _
Marshal.ReadInt32(New IntPtr(pCryptKeyProvInfo.ToInt32 + 8)), _
Marshal.PtrToStringUni(New IntPtr(Marshal.ReadInt32(New IntPtr(pCryptKeyProvInfo.ToInt32 + 4)))), _
Marshal.PtrToStringUni(New IntPtr(Marshal.ReadInt32(pCryptKeyProvInfo))))

' Free the unmanaged CRYPT_KEY_PROV_INFO buffer.
'
Marshal.FreeHGlobal(pCryptKeyProvInfo)
Return New RSACryptoServiceProvider(CspParams)

Catch ex As Exception
MessageBox.Show(ex.Message)
End Try

End If
End If
Return Nothing

End Function

#End Region

End Class


</SAMPLE>



I hope this helps.


Cheers,



Alex (Alejandro Campos Magencio)

Original URL: https://blogs.msdn.microsoft.com/alejacma/2007/11/23/pinvoking-cryptoapi-in-net-c-version/
Post name: P/Invoking CryptoAPI in .NET (C# version)
Original author: Alejandro Campos Magencio
Posting date: 2007-11-23T06:52:00+00:00


Hi, welcome back,


Sometimes weneed to call CryptoAPIfrom .NET becauseclasses inSystem.Security.Cryptography namespace have their limitations.For instance, we can'tcreate a temporary key container with RSACryptoServiceProvider, but we can do it with CRYPT_VERIFYCONTEXT flag and CryptAcquireContext API. RSACryptoServiceProvider will end up calling CryptAcquireContext, but we can't pass CRYPT_VERIFYCONTEXTto it.



You can find more info about all this here in MSDN:


Extending .NET Cryptography with CAPICOM and P/Invoke



Here you have themost common P/Invoke CryptoAPI declarations I've successfully used in the past:



<SAMPLE>

using System;
using System.Runtime.InteropServices;

public class Crypto
{
#region CONSTS

// #define PRIVATEKEYBLOB 0x7
public const Int32 PRIVATEKEYBLOB = 0x7;

// #define AT_KEYEXCHANGE 1
public const Int32 AT_KEYEXCHANGE = 1;

// #define AT_SIGNATURE 2
public const Int32 AT_SIGNATURE = 2;

//#define CRYPT_E_NOT_FOUND _HRESULT_TYPEDEF_(0x80092004L)
public const Int32 CRYPT_E_NOT_FOUND = -2146885628;

// #define CERT_PERSONAL_STORE_NAME L"My"
public const string CERT_PERSONAL_STORE_NAME = "My";

// #define CERT_COMPARE_ANY 0
public const Int32 CERT_COMPARE_ANY = 0;

// #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_FIND_ANY (CERT_COMPARE_ANY << CERT_COMPARE_SHIFT)
public const Int32 CERT_FIND_ANY = CERT_COMPARE_ANY << CERT_COMPARE_SHIFT;

// #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 Int32 CRYPT_VERIFYCONTEXT = -268435456; //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_RSA "1.2.840.113549.1.1.1"
public const String szOID_RSA_RSA = "1.2.840.113549.1.1.1";

// #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";

// #define RSA_CSP_PUBLICKEYBLOB ((LPCSTR) 19)
public const Int32 RSA_CSP_PUBLICKEYBLOB = 19;

// #define X509_PUBLIC_KEY_INFO ((LPCSTR) 8)
public const Int32 X509_PUBLIC_KEY_INFO = 8;

#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 Byte[] 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;
}

// typedef struct _CRYPT_BIT_BLOB
// {
// DWORD cbData;
// BYTE *pbData;
// DWORD cUnusedBits;
// } CRYPT_BIT_BLOB;
[StructLayout(LayoutKind.Sequential)]
public struct CRYPT_BIT_BLOB
{
public Int32 cbData;
public IntPtr pbData;
public Int32 cUnusedBits;
}

// typedef struct _CERT_PUBLIC_KEY_INFO
// {
// CRYPT_ALGORITHM_IDENTIFIER Algorithm;
// CRYPT_BIT_BLOB PublicKey;
// } CERT_PUBLIC_KEY_INFO;
[StructLayout(LayoutKind.Sequential)]
public struct CERT_PUBLIC_KEY_INFO
{
public CRYPT_ALGORITHM_IDENTIFIER Algorithm;
public CRYPT_BIT_BLOB PublicKey;
}

#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
);

// BOOL WINAPI CryptEncodeObject(
// DWORD dwCertEncodingType,
// LPCSTR lpszStructType,
// const void* pvStructInfo,
// BYTE* pbEncoded,
// DWORD* pcbEncoded
// );
[DllImport("Crypt32.dll", SetLastError=true)]
public static extern Boolean CryptEncodeObject (
Int32 dwCertEncodingType,
Int32 lpszStructType,
ref CERT_PUBLIC_KEY_INFO pvStructInfo,
Byte[] pbEncoded,
ref Int32 pcbEncoded
);

[DllImport("Crypt32.dll", SetLastError=true)]
public static extern Boolean CryptEncodeObject (
Int32 dwCertEncodingType,
Int32 lpszStructType,
Byte[] pvStructInfo,
IntPtr pbEncoded,
ref Int32 pcbEncoded
);

// PCCERT_CONTEXT WINAPI CertCreateCertificateContext(
// DWORD dwCertEncodingType,
// const BYTE* pbCertEncoded,
// DWORD cbCertEncoded
// );
[DllImport("Crypt32.dll", SetLastError=true)]
public static extern IntPtr CertCreateCertificateContext (
Int32 dwCertEncodingType,
Byte[] pbCertEncoded,
Int32 cbCertEncoded
);

// BOOL WINAPI CryptAcquireCertificatePrivateKey(
// PCCERT_CONTEXT pCert,
// DWORD dwFlags,
// void* pvReserved,
// HCRYPTPROV* phCryptProv,
// DWORD* pdwKeySpec,
// BOOL* pfCallerFreeProv
// );
[DllImport("Crypt32.dll", SetLastError=true)]
public static extern Boolean CryptAcquireCertificatePrivateKey (
IntPtr pCert,
Int32 dwFlags,
IntPtr pvReserved,
ref IntPtr phCryptProv,
ref Int32 pdwKeySpec,
ref Boolean pfCallerFreeProv
);

// BOOL WINAPI CryptHashData(
// HCRYPTHASH hHash,
// BYTE* pbData,
// DWORD dwDataLen,
// DWORD dwFlags
// );
[DllImport("Advapi32.dll", SetLastError=true)]
public static extern Boolean CryptHashData (
IntPtr hHash,
Byte[] pbData,
Int32 dwDataLen,
Int32 dwFlags
);

// BOOL WINAPI CryptSignHash(
// HCRYPTHASH hHash,
// DWORD dwKeySpec,
// LPCTSTR sDescription,
// DWORD dwFlags,
// BYTE* pbSignature,
// DWORD* pdwSigLen
// );
[DllImport("Advapi32.dll", SetLastError=true)]
public static extern Boolean CryptSignHash(
IntPtr hHash,
Int32 dwKeySpec,
String sDescription,
Int32 dwFlags,
Byte[] pbSignature,
ref Int32 pdwSigLen
);

// BOOL WINAPI CryptGetUserKey(
// HCRYPTPROV hProv,
// DWORD dwKeySpec,
// HCRYPTKEY* phUserKey
// );
[DllImport("Advapi32.dll", SetLastError=true)]
public static extern Boolean CryptGetUserKey(
IntPtr hProv,
Int32 dwKeySpec,
ref IntPtr phUserKey
);

#endregion

}

</SAMPLE>


I hope this helps.


Cheers,



Alex (Alejandro Campos Magencio)



PS: A new version of .NET Framework is coming out while you read this. Hopefully we won't need to use CryptoAPI directly as often as we did with .NET Framework 1.1/2.0.


PS: I also have VB.NET declarations. I will post them soon.

Original URL: https://blogs.msdn.microsoft.com/alejacma/2007/11/13/how-to-debug-lsass-exe-process/
Post name: How to debug LSASS.exe process
Original author: Alejandro Campos Magencio
Posting date: 2007-11-13T11:20:00+00:00


Hi, welcome back,

I've been dealing these dayswith an issue about a Custom Authentication Packagewhich was crashing LSASS.exe process even before we had the opportunity to log on the machine. So, how can I debug the package/LSASS processwith my favorite debugger, WinDbg (Debugging Tools for Windows),to know what's going on there?

To make things easier I use two machines: a Windows XP machine running on Virtual PCand my Windows Vista machine. Virtual PC makes my life much easier as I can recover the machine very easily if I "break" it. It also makes kernel debugging easier as I don't need any cables to connect the machines involved. The target package/LSASSprocesswill run on WinXP, and WinDbg will run on Vista.

1) Let's configure LSASS on WinXP to load and use the problematic package (i.e. MyPackage.dll):

1.1) Copy MyPackage.dll to %SystemRoot%\system32.

1.2) Add "MyPackage" to the Authentication Packages list in the \HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa registry key.

2) Let's configure WinXP to run LSASS under a user mode debugger like NTSD.exe (Debugging Tools for Windows). We won't be able to use this debugger directly, but we will be able to use it through WinDbg working as kernel mode debugger on Vista.

2.a) Set Debugger value to REG_SZ "ntsd -d" in HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\lsass.exe.

2.b) Instead of manipulating theregistry directly, we may use GFlags.exe (Debugging Tools for Windows) to make these changes: go to Image File tab, enter "LSASS.exe" in Image field, press TAB to refresh, click on Debugger checkbox and enter "ntsd -d" as the debugger.

After these changes NTSD will break in LSASS execution just whenLSASS is about to start (thx to -d parameter), so we can debug it from the very beginning of its execution. Now we'll need a kernel debugger (WinDbg in our case) to control NTSD remotely.

3) Let's configure WinXP to start on debug mode and be able to attach a kernel debugger to it:

3.1) Run msconfig.exe (System Configuration utility), go to BOOT.INI tab, click on Advanced Options... button, and select /DEBUG, select&set/DEBUGPORT= to COM1:,and select & set /BAUDRATE= to 115200.

3.2) On Virtual PC go to Edit > Settings menu option, select COM1 and set it to a Named pipe called i.e. \\.\pipe\machinename.

Now our WinXP is prepared to be debugged. We can restart it now. We will see that WinXP hangs before showing the logon screen. NTSD has broken in LSASS, and because LSASS is not executing, WinXP won't start either. NTSD is now waiting for our debugging commands, but we will need WinDbg to send those commands to it.

4) Let's configure WinDbg on Vista to do kernel debugging on WinXP:

On WinDbg go to File > Kernel Debug... menu option, select COM tab, check Pipe checkbox, set Baud Rate to 115200 and Port to \\.\pipe\machinename(the same we used on Virtual PC). When we click OK WinDbg will connect to WinXP as its kernel debugger.

When WinDbg connects to WinXP and WinLogon is about to start, WinDbg shows the prompt of NTSD ("Input>"). We will now be able to send commands to NTSD, like bp to set a breakpoint, etc.

Please take a look to "Controlling the User-Mode Debugger from the Kernel Debugger" topic on WinDbg's help for more info on how to control NTSD from WinDbg.

We will now be able to do user mode (thx to NTSD) and kernel mode debugging at the same time with WinDbg.

Note: I had some issues to load the right symbols (.pdb files), because I couldn't set .sympath on NTSD to c:\symbols, for instance. So I did the following: I took a dump of LSASS process with .dump command, I opened the dump and loaded all the symbols I needed (i.e. lsasrv.pdb, lsass.pdb, kernel32.pdb, ntdll.pdb and MyPackage.pdb). I copied all those symbols to System32 folder on XP, and after that NTSD was able to find them without setting its .sympath.

Note: We may debug CSRSS and WinLogon processes following the same principles. Take a look to "Debugging CSRSS with NTSD" and "Debugging WinLogon with NTSD" topics on WinDbg's help.

I hope this helps.

Alex