繁体   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