【发布时间】:2020-02-18 04:12:02
【问题描述】:
我试图在 C# 中实现一个简单的 RSA 签名算法,只使用 BigInteger,没有内置加密工具。为了签署一条消息,我用私钥对其进行加密,为了验证它,我用公钥对其进行解密。在下面的代码中,我注意到一个非常奇怪的行为。对于某些输入字符串(例如“Test”),它会成功验证签名,但对于其他字符串(例如“Test1”),它会失败。
我注意到,只有当m 变量(消息的哈希值)为负数时它才会失败,这会导致解密后的ver 变量变成一个非常大的数字,并且代码打印“错误签名”。
// Generating RSA keys
var random = new Random();
var p = new BigInteger(256, 100, random);
var q = new BigInteger(256, 100, random);
var n = p.Multiply(q);
var phi = p.Subtract(BigInteger.One).Multiply(q.Subtract(BigInteger.One));
var e = new BigInteger("65537");
var d = e.ModInverse(phi);
// Preparing the message
var messageHash = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("Test"));
var m = new BigInteger(messageHash);
// Signing the message
var signature = m.ModPow(d, n);
// Verifying the message
var ver = signature.ModPow(e, n);
Console.Out.WriteLine(m);
Console.Out.WriteLine(ver);
if(ver.Equals(m))
Console.Out.WriteLine("Valid Signature");
else
Console.Out.WriteLine("Wrong Signature");
我将 BouncyCastle 用于 BigInteger 类型。
消息“测试”的示例输出:
16928957987407306249184430693954511195
16928957987407306249184430693954511195
Valid Signature
消息“Test1”的示例输出:
-40249184872970767997805928798048797124
10061048024793920770364189111057222210443355984675629704584018449091407182950576678391694061743052292040531884029654111183675927763342349593675935744009443
Wrong Signature
我认为错误是在签名过程中的某个地方,而不是在验证中。也许我不应该尝试加密负数?如果哈希是负数怎么办?如何修复此代码,使其在任何输入字符串上都能可靠运行?
【问题讨论】:
-
RSA 算法需要
0 <= m < n用于消息m和模数n, here。为了防止出现负数,可以使用var m = new BigInteger(1, messageHash);,它会创建相应的无符号值而不是有符号值。 -
@Topaco 谢谢,你解决了我的问题。如果您发布答案,我会接受。
-
请注意,“教科书”RSA,其中签名和验证与加密和解密是相同的操作,它并不安全,并且不用于真实系统。
-
@Damien_The_Unbeliever 实际上,有一套来自一家非常知名的大公司的专业软件,它使用这种精确的算法来验证许可证密钥。出于明显的原因,我不会在这里提及他们的名字,但你可以相信我,我已经看到了。
标签: c# encryption rsa digital-signature