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
相关产品推荐
相关产品推荐

