Я пытаюсь преобразовать какой-то старый код 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?