如何以编程方式创建用于加密的 X509 存储密钥?
How can I create an X509 Store key programmatically for use in encryption?
我有一项服务需要加密和解密连接文本。我不想硬编码密码,所以我决定使用证书,但我希望能够在第一次设置时将它添加到商店 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);
}
}
}
当我尝试检索 public 密钥时,我 运行 遇到了问题
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);
我现在可以获取 public 密钥,但读取异常
"The parameter is incorrect"
at System.Security.Cryptography.NCryptNative.EncryptData[T](SafeNCryptKeyHandle key, Byte[] data, T& paddingInfo, AsymmetricPaddingMode paddingMode, NCryptEncryptor`1 encryptor)
我打电话给 publicKey.Encrypt
。
由于您显然加密了 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)。
我有一项服务需要加密和解密连接文本。我不想硬编码密码,所以我决定使用证书,但我希望能够在第一次设置时将它添加到商店 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);
}
}
}
当我尝试检索 public 密钥时,我 运行 遇到了问题
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);
我现在可以获取 public 密钥,但读取异常
"The parameter is incorrect"
at System.Security.Cryptography.NCryptNative.EncryptData[T](SafeNCryptKeyHandle key, Byte[] data, T& paddingInfo, AsymmetricPaddingMode paddingMode, NCryptEncryptor`1 encryptor)
我打电话给 publicKey.Encrypt
。
由于您显然加密了 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)。