使用 CryptoAPI 在 Store C# 中通过哈希查找证书

发布于 2024-11-26 23:43:04 字数 6746 浏览 0 评论 0 原文

我想使用 CryptoAPI P/Invoke 从 Store 获取证书。但我遇到了一些问题。
我可以开店,但找不到证书。我不明白为什么。相同的代码适用于 C++。
我想使用 CryptoAPI,因为 .NET 只能使用可导出密钥标记为“yes”的证书密钥

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;

namespace capp
{
    public class Crypto
    {
        #region CONSTS

        // #define CERT_COMPARE_SHIFT        16
        public const Int32 CERT_COMPARE_SHIFT = 16;

        // #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_COMPARE_SHA1_HASH      1
        public const Int32 CERT_COMPARE_SHA1_HASH = 1;

        // #define CERT_FIND_SHA1_HASH     (CERT_COMPARE_SHA1_HASH << CERT_COMPARE_SHIFT)
        public const Int32 CERT_FIND_SHA1_HASH = (CERT_COMPARE_SHA1_HASH << CERT_COMPARE_SHIFT);

        // #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_ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;

        #endregion

        #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 struct CRYPTOAPI_BLOB
        {
            public Int32 cbData;
            public Byte[] pbData;
        }

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

        // BOOL WINAPI CertCloseStore(
        //      HCERTSTORE hCertStore,
        //      DWORD dwFlags
        // );
        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern Boolean CertCloseStore(
            IntPtr hCertStore,
            Int32 dwFlags
        );

        // 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,
            ref CRYPTOAPI_BLOB pvFindPara,
            IntPtr pPrevCertContext
        );

        // BOOL WINAPI CertFreeCertificateContext(
        //      PCCERT_CONTEXT pCertContext
        // );
        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern Boolean CertFreeCertificateContext(
            IntPtr pCertContext
        );

        #endregion
    }

    class Program
    {
        const string MY = "MY";

        static void Main(string[] args)
        {
            IntPtr hCertCntxt = IntPtr.Zero;
            IntPtr hStore = IntPtr.Zero;

            hStore = Crypto.CertOpenStore(Crypto.CERT_STORE_PROV_SYSTEM,
                                            Crypto.MY_ENCODING_TYPE,
                                            IntPtr.Zero,
                                            Crypto.CERT_SYSTEM_STORE_CURRENT_USER,
                                            MY);

            Console.WriteLine("Store Handle:\t0x{0:X}", hStore.ToInt32());

            String sha1Hex = "7a0b021806bffdb826205dac094030f8045d4daa";

            // Convert to bin
            int tam = sha1Hex.Length / 2;
            byte[] sha1Bin = new byte[tam];

            int aux = 0;
            for (int i = 0; i < tam; ++i)
            {
                String str = sha1Hex.Substring(aux, 2);
                sha1Bin[i] = (byte)Convert.ToInt32(str, 16);
                aux = aux + 2;
            }

            Crypto.CRYPTOAPI_BLOB cryptBlob;
            cryptBlob.cbData = sha1Bin.Length;
            cryptBlob.pbData = sha1Bin;

            if (hStore != IntPtr.Zero)
            {
                Console.WriteLine("Inside Store");
                hCertCntxt = Crypto.CertFindCertificateInStore(
                                       hStore,
                                       Crypto.MY_ENCODING_TYPE,
                                       0,
                                       Crypto.CERT_FIND_SHA1_HASH,
                                       ref cryptBlob,
                                       IntPtr.Zero);

                if (hCertCntxt != IntPtr.Zero)
                    Console.WriteLine("Certificate found!");
                else
                    Console.WriteLine("Could not find ");
            }

            if (hCertCntxt != IntPtr.Zero)
                Crypto.CertFreeCertificateContext(hCertCntxt);
            if (hStore != IntPtr.Zero)
                Crypto.CertCloseStore(hStore, 0);
        }
    }
}

将 CrytpoAPI 映射到 C# http://blogs.msdn.com/b/alejacma/archive/2007/11/23/p-invoking-cryptoapi-in-net-c-version.aspx

I would like to get certificate from Store using CryptoAPI P/Invoke. But I encountered some problems.
I can open store, but not find certificate. I can not understande why. The same code works on C++.
I would like to use CryptoAPI, because .NET only enable to use key of certificates with key exportable marked "yes"

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;

namespace capp
{
    public class Crypto
    {
        #region CONSTS

        // #define CERT_COMPARE_SHIFT        16
        public const Int32 CERT_COMPARE_SHIFT = 16;

        // #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_COMPARE_SHA1_HASH      1
        public const Int32 CERT_COMPARE_SHA1_HASH = 1;

        // #define CERT_FIND_SHA1_HASH     (CERT_COMPARE_SHA1_HASH << CERT_COMPARE_SHIFT)
        public const Int32 CERT_FIND_SHA1_HASH = (CERT_COMPARE_SHA1_HASH << CERT_COMPARE_SHIFT);

        // #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_ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING;

        #endregion

        #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 struct CRYPTOAPI_BLOB
        {
            public Int32 cbData;
            public Byte[] pbData;
        }

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

        // BOOL WINAPI CertCloseStore(
        //      HCERTSTORE hCertStore,
        //      DWORD dwFlags
        // );
        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern Boolean CertCloseStore(
            IntPtr hCertStore,
            Int32 dwFlags
        );

        // 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,
            ref CRYPTOAPI_BLOB pvFindPara,
            IntPtr pPrevCertContext
        );

        // BOOL WINAPI CertFreeCertificateContext(
        //      PCCERT_CONTEXT pCertContext
        // );
        [DllImport("Crypt32.dll", SetLastError = true)]
        public static extern Boolean CertFreeCertificateContext(
            IntPtr pCertContext
        );

        #endregion
    }

    class Program
    {
        const string MY = "MY";

        static void Main(string[] args)
        {
            IntPtr hCertCntxt = IntPtr.Zero;
            IntPtr hStore = IntPtr.Zero;

            hStore = Crypto.CertOpenStore(Crypto.CERT_STORE_PROV_SYSTEM,
                                            Crypto.MY_ENCODING_TYPE,
                                            IntPtr.Zero,
                                            Crypto.CERT_SYSTEM_STORE_CURRENT_USER,
                                            MY);

            Console.WriteLine("Store Handle:\t0x{0:X}", hStore.ToInt32());

            String sha1Hex = "7a0b021806bffdb826205dac094030f8045d4daa";

            // Convert to bin
            int tam = sha1Hex.Length / 2;
            byte[] sha1Bin = new byte[tam];

            int aux = 0;
            for (int i = 0; i < tam; ++i)
            {
                String str = sha1Hex.Substring(aux, 2);
                sha1Bin[i] = (byte)Convert.ToInt32(str, 16);
                aux = aux + 2;
            }

            Crypto.CRYPTOAPI_BLOB cryptBlob;
            cryptBlob.cbData = sha1Bin.Length;
            cryptBlob.pbData = sha1Bin;

            if (hStore != IntPtr.Zero)
            {
                Console.WriteLine("Inside Store");
                hCertCntxt = Crypto.CertFindCertificateInStore(
                                       hStore,
                                       Crypto.MY_ENCODING_TYPE,
                                       0,
                                       Crypto.CERT_FIND_SHA1_HASH,
                                       ref cryptBlob,
                                       IntPtr.Zero);

                if (hCertCntxt != IntPtr.Zero)
                    Console.WriteLine("Certificate found!");
                else
                    Console.WriteLine("Could not find ");
            }

            if (hCertCntxt != IntPtr.Zero)
                Crypto.CertFreeCertificateContext(hCertCntxt);
            if (hStore != IntPtr.Zero)
                Crypto.CertCloseStore(hStore, 0);
        }
    }
}

Reference link to map CrytpoAPI to C# http://blogs.msdn.com/b/alejacma/archive/2007/11/23/p-invoking-cryptoapi-in-net-c-version.aspx

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

白鸥掠海 2024-12-03 23:43:04

您不能只是重新定义 CertFindCertificateInStore 来获取 ref CRYPTOAPI_BLOB

可能有一种更简单的方法,但是如果您使用这些定义:

[StructLayout(LayoutKind.Sequential)]
public struct CRYPTOAPI_BLOB
{
    public Int32 cbData;
    public IntPtr pbData;
}

[DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CertFindCertificateInStore(
    IntPtr hCertStore,
    Int32 dwCertEncodingType,
    Int32 dwFindFlags,
    Int32 dwFindType,
    IntPtr pvFindPara,
    IntPtr pPrevCertContext
);

并像这样调用它们:

Crypto.CRYPTOAPI_BLOB cryptBlob;
cryptBlob.cbData = sha1Bin.Length;
GCHandle h1 = default(GCHandle);
GCHandle h2 = default(GCHandle);
try{
  h1 = GCHandle.Alloc(sha1Bin, GCHandleType.Pinned);
  cryptBlob.pbData = h1.AddrOfPinnedObject();
  h2 = GCHandle.Alloc(cryptBlob, GCHandleType.Pinned);
  hCertCntxt = Crypto.CertFindCertificateInStore(
                                   hStore,
                                   Crypto.MY_ENCODING_TYPE,
                                   0,
                                   Crypto.CERT_FIND_SHA1_HASH,
                                   h2.AddrOfPinnedObject(),
                                   IntPtr.Zero);
}
finally{
  if(h1!=default(GCHandle)) h1.Free();
  if(h2!=default(GCHandle)) h2.Free();
}

,它应该可以工作。

You can't just redefine CertFindCertificateInStore to take a ref CRYPTOAPI_BLOB.

There might be an easier way, but if you use these definitions:

[StructLayout(LayoutKind.Sequential)]
public struct CRYPTOAPI_BLOB
{
    public Int32 cbData;
    public IntPtr pbData;
}

[DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CertFindCertificateInStore(
    IntPtr hCertStore,
    Int32 dwCertEncodingType,
    Int32 dwFindFlags,
    Int32 dwFindType,
    IntPtr pvFindPara,
    IntPtr pPrevCertContext
);

and call them like this:

Crypto.CRYPTOAPI_BLOB cryptBlob;
cryptBlob.cbData = sha1Bin.Length;
GCHandle h1 = default(GCHandle);
GCHandle h2 = default(GCHandle);
try{
  h1 = GCHandle.Alloc(sha1Bin, GCHandleType.Pinned);
  cryptBlob.pbData = h1.AddrOfPinnedObject();
  h2 = GCHandle.Alloc(cryptBlob, GCHandleType.Pinned);
  hCertCntxt = Crypto.CertFindCertificateInStore(
                                   hStore,
                                   Crypto.MY_ENCODING_TYPE,
                                   0,
                                   Crypto.CERT_FIND_SHA1_HASH,
                                   h2.AddrOfPinnedObject(),
                                   IntPtr.Zero);
}
finally{
  if(h1!=default(GCHandle)) h1.Free();
  if(h2!=default(GCHandle)) h2.Free();
}

, it should work.

临走之时 2024-12-03 23:43:04

如果您使用 .Net 那么为什么不使用“System.Security.Cryptography”来执行此操作?

例子:

X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2 cert = store.Certificates
        .Find(X509FindType.FindByThumbprint, thumbprint, false)
        .OfType<X509Certificate2>()
        .FirstOrDefault();

If you are using .Net then why not use "System.Security.Cryptography" to do this?

Example:

X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2 cert = store.Certificates
        .Find(X509FindType.FindByThumbprint, thumbprint, false)
        .OfType<X509Certificate2>()
        .FirstOrDefault();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文