You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RSA不同密钥长度签名与验签匹配问题(C#)

RSA签名验签密钥长度疑问

我知道在RSA算法中,密钥长度决定了破解加密或伪造签名的难度,但我有个疑问:为什么用1024位密钥生成数字签名后,用2048位密钥的RSACryptoServiceProvider验签仍能得到匹配结果?

我用RSACryptoServiceProvider以1024位密钥签名,再用2048位密钥的RSACryptoServiceProvider验签(反过来操作也一样),结果始终匹配。相关代码如下:

签名代码

private static string SignData(string originalMessage, string privateKey, int keyLength)
{
    using var rsa = new RSACryptoServiceProvider(keyLength);
    rsa.FromXmlString(privateKey);

    var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
    rsaFormatter.SetHashAlgorithm("SHA256");

    var sha256Managed = new SHA256Managed();
    var signedHashValue = rsaFormatter.CreateSignature(sha256Managed.ComputeHash(new UnicodeEncoding().GetBytes(originalMessage)));
    var signature = Convert.ToBase64String(signedHashValue);

    return signature;
}

验签代码

private static bool VerifyData(string stringSigned, byte[] signature, XmlElement rsaPublicKey, int keyLength)
{
    using var rsa = new RSACryptoServiceProvider(keyLength);
    rsa.FromXmlString(rsaPublicKey.OuterXml);

    var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
    rsaDeformatter.SetHashAlgorithm("SHA256");

    var sha256Managed = new SHA256Managed();
    if (rsaDeformatter.VerifySignature(sha256Managed.ComputeHash(new UnicodeEncoding().GetBytes(stringSigned)), signature))
        return true;

    return false;
}

测试代码

static void Main(string[] args)
{
    const int signingKey = 1024;
    const int verifyingKey = 2048;
    const string originalMessage = "textToCheck";

    var rsaForSigning = new RSACryptoServiceProvider(signingKey);
    var publicKey = rsaForSigning.ToXmlString(false);
    var privateKey = rsaForSigning.ToXmlString(true);

    // Sign with private key
    var signature = SignData(originalMessage, privateKey, signingKey);

    // Verify signature with public key
    var doc = new XmlDocument();
    doc.LoadXml(publicKey);

    var correctSignature = VerifyData(originalMessage, Convert.FromBase64String(signature), doc.DocumentElement, verifyingKey);
    if (correctSignature)
        Console.WriteLine($"{originalMessage} - Signature is valid");
    else
        Console.WriteLine($"{originalMessage} - Signature is NOT valid");

    Console.WriteLine("Done!");
    Console.ReadKey();
}

问题原因解析

你看到的现象核心原因是:调用RSACryptoServiceProvider.FromXmlString()时,构造函数传入的keyLength参数会被导入的密钥实际长度覆盖。

具体来说:

  • 签名方法中,你创建了指定keyLength的RSACryptoServiceProvider实例,但紧接着调用FromXmlString(privateKey)导入了1024位私钥,此时实例会自动切换为使用1024位密钥执行签名操作,构造函数的参数只是初始值,实际被导入的密钥覆盖。
  • 验签方法中同理,你创建了2048位的RSACryptoServiceProvider实例,但导入的是对应1024位私钥的公钥,实例会自动适配为1024位密钥完成验签,构造函数的2048参数并未实际生效。

本质上,你始终是用**同一对密钥(1024位私钥+对应公钥)**完成签名和验签,所以结果自然匹配。如果用完全无关的2048位公钥去验证1024位私钥的签名,结果肯定不匹配。

另外补充:RSACryptoServiceProvider是较旧的API,推荐在.NET Core/.NET 5+环境中使用RSA.Create()方法替代,它的行为更直观,也能避免这类易混淆的参数问题。


内容的提问来源于stack exchange,提问作者Angela Calborean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 04:23:39