簡體   English   中英

如何以編程方式在 windows 密鑰庫中使用 X509 證書創建不可導出的私鑰 (C#)

[英]How to create non-exportable private key with X509 certificate in windows key store programmatically (C#)

我正在嘗試創建一個私鑰並添加一個證書(自簽名或從 CA 簽名),我應該只能在其中導出證書並在 C# 中使私鑰不可導出。也就是說,如果有人試圖從certmgr導出證書,導出選項將被禁用,如下圖所示-

在此處輸入圖像描述

我希望在創建它時以編程方式在 C# 中使用相同的不可導出選項。 當使用 Crypto Shell Extensions when Mark this Key is exportable未選中時安裝 .pfx/.p12 文件時,私鑰通常變得不可導出。

在此處輸入圖像描述

我可以成功創建密鑰對並在 windows 密鑰庫中添加證書條目。 但是,是的,導出私鑰選項始終處於啟用狀態,即我無法限制導出私鑰。 我試過這個 -

        public void init(){
            AsymmetricCipherKeyPair asymmetricCipherKeyPair = GetKeyPair();

            X509Name issuer = this.GenerateRelativeDistinguishedName("test org");
            X509Name subject = this.GenerateRelativeDistinguishedName("test user1");


            Org.BouncyCastle.X509.X509Certificate cert = GenerateCertificate(issuer, subject, asymmetricCipherKeyPair.Private, asymmetricCipherKeyPair.Public);
            importSelfSignedCert(asymmetricCipherKeyPair, cert);
        }
        
        private AsymmetricCipherKeyPair GetKeyPair()
        {
            return new Pkcs1xHandler().GenerateKeyPair(Constants.RsaKeyLength.Length2048Bits);
        }
         
        protected X509Name GenerateRelativeDistinguishedName(String commonName)
        {

            IDictionary attributes = new Hashtable();
            IList ordering;

            attributes.Add(X509Name.CN, commonName);

            ordering = new ArrayList(attributes.Keys);
            return new X509Name(ordering, attributes);
        }


        protected void importSelfSignedCert(AsymmetricCipherKeyPair asymmetricCipherKeyPair, Org.BouncyCastle.X509.X509Certificate cert)
        {
            try
            {
                int ID =1;
                AsymmetricCipherKeyPair ackp = asymmetricCipherKeyPair;
                var rsaPriv = Org.BouncyCastle.Security.DotNetUtilities.ToRSA(ackp.Private as RsaPrivateCrtKeyParameters);

                // Setup RSACryptoServiceProvider with "KeyContainerName" set to "KeyContainer"+ enrollmentID
                var csp = new CspParameters();
                csp.KeyContainerName = "TestPrivKey" + ID;
                csp.Flags |= CspProviderFlags.UseMachineKeyStore;

                var rsaPrivate = new RSACryptoServiceProvider(csp);

                // Import private key to windows keystrore, from already generated BouncyCastle rsa privatekey
                rsaPrivate.ImportParameters(rsaPriv.ExportParameters(true));
                //Console.Write("rsaprivate key:" + rsaPrivate.ToXmlString(true));

                System.Security.Cryptography.X509Certificates.X509Certificate2 certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2();
                var flags = X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.UserKeySet;
                certificate.Import(cert.GetEncoded(), String.Empty, flags);
                certificate.PrivateKey = rsaPrivate;


                // opening up the windows cert store because thats where I want to save it.
                System.Security.Cryptography.X509Certificates.X509Store store = new System.Security.Cryptography.X509Certificates.X509Store(System.Security.Cryptography.X509Certificates.StoreName.My, System.Security.Cryptography.X509Certificates.StoreLocation.CurrentUser);
                store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.MaxAllowed);
                store.Add(certificate);
                store.Close();

                rsaPrivate.PersistKeyInCsp = true; //persisting the key in container is important to retrieve the key later



                ///make non exporable
                csp.Flags = CspProviderFlags.UseNonExportableKey;
                var rsaPrivate2 = new RSACryptoServiceProvider(csp);
                rsaPrivate2.ExportParameters(false); //restrict to export
                rsaPrivate2.PersistKeyInCsp = true;
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine("Error : " + e);
                Console.WriteLine(e);
                Log.Print(LogLevel.High, e.ToString());
            }
        }

當我嘗試導出證書時,我可以選擇是,也導出私鑰,如下圖所示 -

在此處輸入圖像描述

在以編程方式創建私鑰時,有什么方法可以使私鑰像第一張圖片一樣不可導出嗎? 如果有任何提示、參考或代碼示例,我將不勝感激。 謝謝。

要使私鑰不可導出,必須在導入密鑰時另外設置CspProviderFlags.UseNonExportableKey

...
var csp = new CspParameters();
csp.KeyContainerName = "TestPrivKey" + ID;
csp.Flags |= CspProviderFlags.UseMachineKeyStore | CspProviderFlags.UseNonExportableKey; // Fix
var rsaPrivate = new RSACryptoServiceProvider(csp);
rsaPrivate.ImportParameters(rsaPriv.ExportParameters(true));
...

如果這樣做,向導中的是,導出私鑰選項將被禁用。

請注意,在發布的代碼中也設置了該標志,但設置得太晚了,即在證書保存到商店之后。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM