【问题标题】:How can I create an X509 Store key programmatically for use in encryption?如何以编程方式创建 X509 存储密钥以用于加密?
【发布时间】:2020-12-04 14:31:47
【问题描述】:

我有一项服务需要对连接文本进行加密和解密。我不想硬编码密码,所以我决定使用证书,但我希望能够在第一次打开设置 UI(单独的配置应用程序)时将其添加到商店。

我有代码检查现有证书,如果找不到证书,则添加一个新证书。

    private static void GenerateNewSecurityCertificate()
    {
        var ecdsa = ECDsa.Create(); // generate asymmetric key pair
        var request = new CertificateRequest($"cn={CertificateName}", ecdsa, HashAlgorithmName.SHA512);
        var cert = request.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(50));
        File.WriteAllBytes("c:\\temp\\EncryptionCert.pfx", cert.Export(X509ContentType.Pfx, _certificatePassword));
    }

    private static void AddCertificateToStore()
    {
        using (var store = new X509Store(StoreName.TrustedPublisher, StoreLocation.LocalMachine))
        {
            store.Open(OpenFlags.ReadWrite);
            using (var cert = new X509Certificate2("c:\\temp\\EncryptionCert.pfx", _certificatePassword,
                X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet))
            {
                store.Add(cert);
            }
        }
    }

我在尝试检索公钥时遇到了问题

using (var store = new X509Store(StoreName.TrustedPublisher, StoreLocation.LocalMachine))
{
    store.Open(OpenFlags.ReadOnly);
    using (var cert = store.Certificates.Find(X509FindType.FindBySubjectName, CertificateName, false)[0])
    {
        var publicKey = cert.GetRSAPublicKey();
        encryptedKey = publicKey.Encrypt(aesKey.Key, RSAEncryptionPadding.OaepSHA512);
    }
}

当我调用cert.GetRSAPublicKey() 时,我得到一个空值返回。有谁知道我可能做错了什么?

更新:

我更新了GenerateNewSecurityCertificate 阅读

var rsa = RSA.Create(); 
var request = new CertificateRequest($"cn={CertificateName}", rsa, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1); 

我现在可以获取公钥,但读取异常

"The parameter is incorrect" 
at System.Security.Cryptography.NCryptNative.EncryptData[T](SafeNCryptKeyHandle key, Byte[] data, T& paddingInfo, AsymmetricPaddingMode paddingMode, NCryptEncryptor`1 encryptor) 

我打电话给publicKey.Encrypt

【问题讨论】:

  • 您在GenerateNewSecurityCertificate 中创建了一个ECDSA 密钥对,但最后导出了一个(公共)RSA 密钥。使用 RSA 或 EC。对于 EC 密钥,还有其他检索方法,例如GetPublicKey / GetPublicKeyString 以二进制/十六进制编码格式返回(未压缩的)原始 EC 公钥。使用 GetRSAPublicKey 检索公共 RSA 密钥。
  • @Topaco - 感谢您的回复。我更新了 GenerateNewSecurityCertificate 以读取 var rsa = RSA.Create(); var request = new CertificateRequest($"cn={CertificateName}", rsa, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);我现在可以获取公钥,但在调用 publicKey.Encrypt 时会出现“参数不正确”的异常。在 System.Security.Cryptography.NCryptNative.EncryptData[T](SafeNCryptKeyHandle key, Byte[] data, T& paddingInfo, AsymmetricPaddingMode paddingMode, NCryptEncryptor`1 加密器)
  • 这可能是由于选择了关键参数,请看我的回答。
  • 您需要增加 RSA 密钥大小(@Topaco 的回答)或减少 OAEP 填充大小(例如,使用 OAEP-SHA256)。您可能正在尝试存储 32 个字节,将其与 crypto.stackexchange.com/a/42100/36951 的图表进行比较。
  • @bartonjs - 我在回答中提到了较小摘要的替代方案。但是由于 OP 使用 1024 位密钥(并且只有使用此密钥大小,问题才会在加密 AES 密钥的上下文中实际发生),在我看来这是错误的方式here,因为现在 1024 位密钥太小了。

标签: c# encryption x509 encryption-symmetric


【解决方案1】:

由于您显然加密了 AES 密钥,因此可以假设数据的(最大)长度为 32 字节 (AES-256)。可以重现错误消息,例如如果消息对于所使用的密钥来说太大。

对于 RSA,消息的长度不得超过密钥长度。事实上,它甚至更小,因为允许长度的一部分被保留用于填充。对于 OAEP,这部分取决于使用的摘要。对于 SHA512,保留部分(130 字节)太大,以至于 1024 位(128 字节)密钥是不够的,使用 2048 位(256 字节)密钥,消息可能仍然是 126 字节大,请参阅here

您使用

创建一个 RSA 密钥
var rsa = RSA.Create(); 

使用默认值作为密钥长度,s。 RSA.Create()。此默认值还取决于 .NET 版本。在 .NET Framework 4.8 下,在我的机器上创建了一个 1024 位密钥(现在太短了),在 .NET Core 3.1 下创建了一个 2048 位密钥。您可以使用rsa.KeySize查看密钥长度。

可能在您的环境中生成了一个对您的目的来说太短的密钥。最好不要依赖默认值,而是明确指定值。 Create 方法具有使这成为可能的重载,请参阅RSA.Create(Int32)。您应该使用此重载并创建一个(至少 2048 位)的密钥。

或者,理论上可以通过另一个摘要(例如 SHA256)消除该错误。除此之外,出于安全原因,现在(12/2020)不应使用 1024 位的密钥,长度应至少为 2048 位(请参阅here)。

【讨论】:

  • 感谢您的详细解答;我从中学到了很多。我不使用加密,所以这对我来说是全新的。虽然我可以找到很多关于理论的知识,但我无法在 C# 示例代码中找到太多关于如何做到这一点的信息,而且我通过示例学习得更好。您的回答非常有帮助。
猜你喜欢
  • 2017-03-09
  • 2013-06-27
  • 2014-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-07
  • 2016-02-15
  • 1970-01-01
相关资源
最近更新 更多