【问题标题】:Use RSACng to SignData that's compatible with RSACryptoServiceProvider使用 RSACng 对与 RSACryptoServiceProvider 兼容的数据进行签名
【发布时间】:2020-01-18 03:18:34
【问题描述】:

我正在尝试将一些较旧的 CAPI 代码转换为使用 CNG,特别是为了使用临时私钥来补充证书。 (据我了解,CAPI 不支持。)

我们使用证书的私钥 (PK) 对数据进行签名。我希望这两种实现能够产生兼容的输出,但令我惊讶的是它们没有。

// Hydrate a cert with PK. Make PK a file-based key so we can get the container and use CAPI.
// (Note, although .NET Framework 4.8, the LangVersion is 8.0 so I can use using.)
using var cert = new X509Certificate2(testCertData, "passwd", X509KeyStorageFlags.MachineKeySet);
// Some arbitrary data to sign.
byte[] data = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 };

byte[] signatureCsp, signatureCng;
// Sign with CAPI. This is what we're doing today.
// The cert PK's crypto provider doesn't support SHA256, so we build a different one.
var csp = (RSACryptoServiceProvider)cert.PrivateKey;
var cp = new CspParameters{
    KeyContainerName = csp.CspKeyContainerInfo.KeyContainerName,
    KeyNumber = csp.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2,
};
using (var rsaCsp = new RSACryptoServiceProvider(cp)) {
    signatureCsp = rsaCsp.Sign(data);
}
// Sign with CNG. This is what I want to do.
using (var rsaCng = cert.GetRSAPrivateKey()) {
    signatureCng = rsaCng.Sign(data);
}
// The signatures are different. In fact they're different lengths, 128 and 256 bytes respectively.
Console.WriteLine(Convert.ToBase64String(signatureCsp));
Console.WriteLine(Convert.ToBase64String(signatureCng));

// But maybe they're compatible? Let's see if code which verifies the first can verify the second.
using (var provider = new RSACryptoServiceProvider(cp)) {
    var verifiedCsp = provider.Verify(data, signatureCsp);
    var verifiedCng = provider.Verify(data, signatureCng);
    Console.WriteLine("RSACryptoServiceProvider verified: {0}", verifiedCsp);
    Console.WriteLine("RSACng signature         verified: {0}", verifiedCng); // Nope. False.
}

为统一起见,以上使用以下扩展方法,将这两种情况视为抽象 RSA 基类型的实现,并具有相同的加密参数。

public static byte[] Sign(this RSA rsa, byte[] buffer) {
    return rsa.SignData(buffer, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}
public static bool Verify(this RSA rsa, byte[] buffer, byte[] signature) {
    return rsa.VerifyData(buffer, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
}

我需要做些什么来使用证书的 CNG 密钥对数据进行签名,以便输出可以被 CAPI 密钥生成的签名的当前消费者验证?

【问题讨论】:

  • 我认为这一切都归结为您重新打开了rsaCsp 的密钥(只需使用csp),而您丢失了机器密钥位。因此,您对密钥的“重新打开”使新的密钥具有默认大小(1024 位)。
  • @bartonjs。不幸的是,这是评论中解释的必要步骤。与导入的证书关联的 CSP 不能使用 SHA256,因此需要使用更新的提供程序打开密钥。我见过明确设置 CspParameters.ProviderName 的示例,但实际上我发现这不是必需的。 AFAIK 这不会产生新的密钥。一方面,每次执行都会产生相同的签名;如果每次运行都重新生成密钥,那么每次运行都会产生不同的签名。
  • 很公平,但您需要在 CspParameters 中设置 MachineKey 标志。您当前的代码在用户范围内打开或创建同名密钥。
  • 确实你是对的!谢谢!我想如果有一个额外的文件,它会在 CSP 被处理时被清理,但不是。所以我添加了Flags = CspProviderFlags.UseMachineKeyStore。关于问题的关键,如何使用 RSA CNG 以与此 CAPI 签名方法兼容的方式进行签名的任何建议?
  • 除了缺少 MachineKey 标志外,其他一切看起来都正确。如果它仍然无法正常工作,那么最好了解一下您所处的状态。

标签: c# rsa sign x509certificate2 cng


【解决方案1】:

您对 RSA 类的使用是正确的,并且会为相应的密钥生成兼容的结果。

这里的问题是你打开 PFX 进入机器密钥存储区:

using var cert = new X509Certificate2(testCertData, "passwd", X509KeyStorageFlags.MachineKeySet);

但是当您重新打开密钥的 RSACryptoServiceProvider 版本时,您没有设置 CspProviderFlags.UseMachineKeyStore 标志。

var cp = new CspParameters{
    KeyContainerName = csp.CspKeyContainerInfo.KeyContainerName,
    KeyNumber = csp.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2,
};

由于您没有设置机器密钥存储标志,它使用了用户密钥存储,并且“打开”密钥创建了一个新密钥(因为以前不存在具有该名称的密钥)。创建一次后,连续运行将重新打开相同的密钥(假设 PFX 导入具有一致的密钥名称)。

var cp = new CspParameters{
    KeyContainerName = csp.CspKeyContainerInfo.KeyContainerName,
    KeyNumber = csp.CspKeyContainerInfo.KeyNumber == KeyNumber.Exchange ? 1 : 2,
    Flags = CspProviderFlags.UseMachineKeyStore | CspProviderFlags.UseExistingKey,
};

【讨论】:

  • 谢谢!我现在已经包含了Flags = cspInfo.MachineKeyStore ? CspProviderFlags.UseMachineKeyStore | CspProviderFlags.UseExistingKey : CspProviderFlags.UseExistingKey var cspInfo = ((RSACryptoServiceProvider)cert.PrivateKey).CspKeyContainerInfo;
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-14
  • 1970-01-01
  • 1970-01-01
  • 2012-02-03
  • 2017-12-05
相关资源
最近更新 更多