为何相同数据下ECDSA生成不同签名而RSA签名一致?
测试现象验证
RSA签名测试用例
示例代码(C#):
byte[] raw = Encoding.Default.GetBytes("Hello, World!"); RSA key = RSA.Create(); for (int index = 0; index < 5; index++) { byte[] signed = key.SignData(raw, HashAlgorithmType.SHA256, RSASignaturePadding.Pkcs1); string hashed = signed.ToSha256String(); Console.WriteLine(hashed); }
输出结果:
043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89
043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89
043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89
043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89
043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89
RSA使用PKCS#1 v1.5填充模式下,相同输入的多次签名输出完全一致。
ECDSA签名测试用例
示例代码(C#):
byte[] raw = Encoding.Default.GetBytes("Hello, World!"); ECDsa key = ECDsa.Create(); for (int index = 0; index < 5; index++) { byte[] signed = key.SignData(raw, HashAlgorithmType.SHA256); string hashed = signed.ToSha256String(); Console.WriteLine(hashed); }
输出结果:
043a718774c572bd8a25adbeb1bfcd5c0256ae11cecf9f9c3f925d0e52beaf89
a31fe9656fc8d3a459e623dc8204e6d0268f8df56d734dac3ca3262edb5db883
a871c47a7f48a12b38a994e48a9659fab5d6376f3dbce37559bcb617efe8662d
d7ef0a04f3c8055644677299a9414a75adcb15916eb48417416c9317ace2ff4f
779f5dd63960abda52a7da70464b92eedd47f84a8dffda2d672e6a99de1bab95
相同私钥、相同输入的前提下,ECDSA多次签名输出完全不同。
差异核心原理
- RSA签名确定性的原因:测试中使用的
RSASignaturePadding.Pkcs1是确定性填充方案,整个签名过程没有引入随机变量,相同私钥、相同明文、相同哈希算法的前提下,每次计算得到的签名结果完全一致。如果改用带随机盐的PSS概率填充方案,RSA也会出现每次签名结果不同的情况。 - ECDSA签名非确定性的原因:ECDSA的签名生成逻辑天然引入了随机变量:签名由
(r, s)两个值组成,生成过程中需要先选一个密码学安全的随机数k,r由k和椭圆曲线基点计算得到,s由k的逆、消息哈希值、私钥、r共同计算得到。常规ECDSA实现默认每次签名都会生成全新的随机k,因此哪怕输入完全相同,每次得到的(r, s)对都会不同,最终的签名结果自然有差异。所有不同的签名都是合法的,都可以通过对应公钥的校验。
如果需要ECDSA生成确定性签名,可以遵循RFC 6979标准,使用消息哈希和私钥派生固定的k代替随机数,即可实现相同输入得到相同签名的效果。
内容的提问来源于stack exchange,提问作者Matthew Layton

