How can I compare public keys in .NET?

情到浓时终转凉″ 提交于 2019-12-04 20:37:07

You can compare the PublicKey property of signing certificates in the SignedXml.KeyIfo with signing key output from SignedXml.CheckSignatureReturningKey. This C# extension method does the job for me:

public static bool CheckSignatureReturningCertificate(this SignedXml signedXml, out X509Certificate2 signingCertificate)
{
    signingCertificate = null;
    AsymmetricAlgorithm signingKey;
    bool isValid = signedXml.CheckSignatureReturningKey(out signingKey);
    if (isValid)
    {
        IEnumerable<X509Certificate2> keyInfoCertificates =
            signedXml.KeyInfo.OfType<KeyInfoX509Data>()
                .SelectMany(x => x.Certificates.Cast<X509Certificate2>());

        signingCertificate = keyInfoCertificates.FirstOrDefault(x => x.PublicKey.Key == signingKey);
        if (signingCertificate == null)
        {
            throw new Exception("Signing certificate not found in KeyInfo.");
        }
    }

    return isValid;
}

Use it like this:

X509Certificate2 signingCertificate = null;
bool isValid = signedXml.CheckSignatureReturningCertificate(out signingCertificate);
if(isValid)
{
    // signingCertificate now contains the certificate used to sign
}
Roger Lipscombe

The public key parameters for the RSA algorithm are {e, n}, the exponent and the modulus. In .NET, these are available from the RSAParameters struct. The other fields represent the private key.

So, to compare an X509Certificate2 and an RSACryptoServiceProvider for public key equality, you can just grab these parameters:

AsymmetricAlgorithm signingKey;
bool signatureIsVerified = signedXml.CheckSignatureReturningKey(out signingKey);

var certificateParameters =
    ((RSA)certificate.PublicKey.Key).ExportParameters(
        includePrivateParameters: false);
var signingParameters = signingKey.ExportParameters(
        includePrivateParameters: false);
bool areEqual =
    ByteArrayEquals(certificateParameters.Exponent,
                    signingParameters.Exponent)
    && ByteArrayEquals(certificateParameters.Modulus,
                    signingParameters.Modulus);

You'll have to implement ByteArrayEquals, because there's no good way to do it in .NET.

If you're using DSA rather than RSA, the public key is made up of {p, q, g, y}.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!