使用 Bouncy Castle ECDsaSigner 进行验证

Validate with Bouncy Castle ECDsaSigner

我正在尝试使用带有 R 和 S 的 eCDsaSigner 验证消息摘要哈希,但 VerifySignature returns 错误 . 是否可以获得有关 eCDsaSigner 失败原因的更多信息?我确信哈希是正确的,因为我重新创建了它并将它与提取的版本进行了比较。 任何人都可以对此有所了解吗?谢谢

// R and S
byte[] der = Hex.Decode("3044021f4043e112eebe8c92c6aee9132f24af6f73c61353dbd1b1cdde2a5429ba4e290221009caf197c3cf9838e72068097409ee23b6648b1b14d44a38a5825495893dcd629");// 3043021f1acda88726e28dbdfcea74e403e7424ba9cba588777e810e42caa5d274135502207283b90135ef09e5847516a9163f4f6a4d403abb9d7632c77397e37165632619");// 3045022100bb3435689a49cb00a04b64fbd7c886d5c67eb406781b43b4ca18bb778df6d35e02201e54c928da6c4867e2b8aafb7703b00784971ef47837433bdf8a6ecb4cdbebcd");

Asn1Sequence seq = Asn1Sequence.GetInstance(der);

BigInteger r = DerInteger.GetInstance(seq[0]).PositiveValue;
BigInteger s = DerInteger.GetInstance(seq[1]).PositiveValue;

// Signature Hash
var signedDataDer = Convert.FromBase64String("MIAGCS...");
var signers = new CmsSignedData(signedDataDer).GetSignerInfos().GetSigners();
var signersEnumerator = signers.GetEnumerator();

signersEnumerator.MoveNext();

SignerInformation signerInfo = (SignerInformation)signersEnumerator.Current;

var messageDigestDer = signerInfo.SignedAttributes[CmsAttributes.MessageDigest].GetDerEncoded();
var messageDigestHash = Asn1OctetString.GetInstance(Asn1Set.GetInstance(Asn1Sequence.GetInstance(messageDigestDer)[1])[0]).GetOctets();

// Verify time
const string clientCertStr = "MIID2D ...";
var clientCertBytes = Convert.FromBase64String(clientCertStr);
var clientCert = new X509Certificate2(clientCertBytes);
Org.BouncyCastle.X509.X509Certificate myx509Certificate = DotNetUtilities.FromX509Certificate(clientCert);

Org.BouncyCastle.Crypto.AsymmetricKeyParameter keyParam = myx509Certificate.GetPublicKey();
Org.BouncyCastle.Crypto.Signers.ECDsaSigner eCDsaSigner = new ECDsaSigner();
eCDsaSigner.Init(false, keyParam);
bool doesItVerify = eCDsaSigner.VerifySignature(messageDigestHash, r, s);

您的方法假定消息摘要属性值已经签名。然而,在签名属性 (signedAttrs) 存在的情况下,这些(包括消息摘要属性)被散列和签名,参见 here, here and for more details RFC5652,sec. 5.1。签名数据类型5.3。 SignerInfo 类型 5.4。消息摘要计算过程,分别

因此,如果您考虑签名属性而不是单独考虑消息摘要属性,则验证成功:

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Cms;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.X509.Store;
using System;
using System.Collections;
using System.Security.Cryptography;

...

// Get signature, get signed attributes
byte[] signedDataDer = Convert.FromBase64String("MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIID3DCCA9gwggNdoAMCAQICEyEAAZd0HpR/sCxFvssAAgABl3QwCgYIKoZIzj0EAwMwRDEVMBMGCgmSJomT8ixkARkWBWxvY2FsMRcwFQYKCZImiZPyLGQBGRYHdGVzdGxhYjESMBAGA1UEAxMJRUNDLVN1YkNBMB4XDTIyMDUwMTE3Mzk1N1oXDTIyMTExNzEwNTQwNVowGjEYMBYGA1UEAxMPQ049RjcxU1Y4UFVIRzdHMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEyLhOpn3E9fLRUmyQjqj4oqYaZCas5XUSFdpybQHlWQdyzG/wpjeIuQmivBtv+UyVUFPiGjDSe10MybZA3FKWw6OCAlYwggJSMB0GA1UdDgQWBBQF6gHIAKZ7RNI2+QmPPrJdFfnUrzAfBgNVHSMEGDAWgBTrjUtVuyh/arwAVWt6WlIqUdpj3jCBzgYDVR0fBIHGMIHDMIHAoIG9oIG6hoG3bGRhcDovLy9DTj1FQ0MtU3ViQ0EoMiksQ049bGFiLXNydjUyLENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPXRlc3RsYWIsREM9bG9jYWw/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3RyaWJ1dGlvblBvaW50MIG9BggrBgEFBQcBAQSBsDCBrTCBqgYIKwYBBQUHMAKGgZ1sZGFwOi8vL0NOPUVDQy1TdWJDQSxDTj1BSUEsQ049UHVibGljJTIwS2V5JTIwU2VydmljZXMsQ049U2VydmljZXMsQ049Q29uZmlndXJhdGlvbixEQz10ZXN0bGFiLERDPWxvY2FsP2NBQ2VydGlmaWNhdGU/YmFzZT9vYmplY3RDbGFzcz1jZXJ0aWZpY2F0aW9uQXV0aG9yaXR5MA4GA1UdDwEB/wQEAwIHgDA9BgkrBgEEAYI3FQcEMDAuBiYrBgEEAYI3FQiD9Z8LhfLocYaBhR+ExrEgg/3he2mC9OoQg8uQBgIBZAIBRTATBgNVHSUEDDAKBggrBgEFBQcDAjAbBgkrBgEEAYI3FQoEDjAMMAoGCCsGAQUFBwMCMAoGCCqGSM49BAMDA2kAMGYCMQCgll9gISIWnd2jYtwZ93dNPyOF8zjlenB2tqOuYzdAQpXrcATLs1qOxvicaX4AaYACMQD/MZP41sJRnw9Pef/gajTZbi2dK8VT+SoxZ9q5bpeFcjoTOkuFcAT/DWWliuLWb0IxggEiMIIBHgIBATBbMEQxFTATBgoJkiaJk/IsZAEZFgVsb2NhbDEXMBUGCgmSJomT8ixkARkWB3Rlc3RsYWIxEjAQBgNVBAMTCUVDQy1TdWJDQQITIQABl3QelH+wLEW+ywACAAGXdDAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjIwNTAxMjAzOTEyWjAjBgkqhkiG9w0BCQQxFgQUhuUgvhtjs/rNrdTNLtWkN7itQg0wCQYHKoZIzj0EAQRHMEUCICZOO0TCJadjqMkTT8InOY+ARfImn0PISSNOWXIw3N9BAiEA2CaoUofu5Z4YYaM7s6x2ZYpI8e99FnaigfeT+DFjfEgAAAAAAAA=");
var signedData = new CmsSignedData(signedDataDer);
var signers = signedData.GetSignerInfos().GetSigners();
IEnumerator signersEnumerator = signers.GetEnumerator();
signersEnumerator.MoveNext();
SignerInformation signerInfo = (SignerInformation)signersEnumerator.Current;
byte[] signatureDer = signerInfo.GetSignature();
byte[] signedAttribs = signerInfo.GetEncodedSignedAttributes(); // message digest attribute included

// Extract r and s from DER signature
Asn1Sequence seq = Asn1Sequence.GetInstance(signatureDer);
BigInteger r = DerInteger.GetInstance(seq[0]).PositiveValue;
BigInteger s = DerInteger.GetInstance(seq[1]).PositiveValue;

// Get certificate (or import the certificate itself as in the posted code)
IX509Store x509Store = signedData.GetCertificates("Collection");
ICollection x509Coll = x509Store.GetMatches(new X509CertStoreSelector());
IEnumerator x509Enumerator = x509Coll.GetEnumerator();
x509Enumerator.MoveNext();
X509Certificate x509 = (X509Certificate)x509Enumerator.Current;

// Verify
AsymmetricKeyParameter keyParameter = x509.GetPublicKey();
ECDsaSigner eCDsaSigner = new ECDsaSigner();
eCDsaSigner.Init(false, keyParameter);
bool doesItVerify = eCDsaSigner.VerifySignature(SHA1.HashData(signedAttribs), r, s); // Fix: consider SHA1 hash of signed attributes
Console.WriteLine(doesItVerify); // true