我的项目正在使用来自某些第三方软件的某些数据集的签名验证。使用的签名算法是SHA1withDSA
。当我使用SDK附带的标准SUN加密提供程序时,一切都很顺利。最近我转到了Bouncy Castle 1.50,之后转了一些以前的数据集(也就是SUN
提供者)经过验证,开始失败,其余的仍然经过验证确定。
我探索了两个提供商的源代码,结果发现SDK的默认提供商对错误形成的签名(虽然能够被恢复)有某种保护,而Bouncy Castle提供商没有它。查看
OpenJDK
for Java 7(第336-344行)或
OpenJDK
for Java 8(第265-273行):在某些情况下,他们已经做了一些签名修复。虽然org.bouncycastle.jcajce.provider.asymmetric.dsa.DSASigner#engineVerify
没有这样做,但在org.bouncycastle.crypto.signers.DSASigner#verifySignature
中明确指出数字必须是正数,否则验证会立即失败。
这是BC的一个错误,还是我错过了什么?要克服
这个,我已经分组了org.bouncycastle.crypto.signers.DSASigner
和
在那里添加了相同的上述签名修复,然后插入此
在另一个签名算法中(通过子类化org.bouncycastle.jcajce.provider.asymmetric.dsa.DSASigner
)。但也许我忽略了另一种方式,这个“问题”是众所周知的?请指教。
答案 0 :(得分:2)
如果ASN.1整数的错误BER / DER编码 - 存储为签名大端,右对齐八位字节 - 确实是罪魁祸首那么Bouncy确实不有一个错误。如果设置了编码的第一位,则应使用00
值字节填充正值,否则它将表示负值。
Sun提供商错误地允许这些签名进行验证,而另一方当然会生成无效签名。请注意,可以让签名验证没有这个"修复"在Sun代码中:只需在将提供给验证函数之前调整编码。
唯一不可能的时候是将DSA验证作为通用签名验证方法从另一个库调用,而不是从可以在调用之前调整数据的应用程序调用。
另一方面,我认为你已经创造了一个优雅的解决方案。唯一的问题是,如果从符合JCA的框架验证提供商的签名,它可能无法运行。另一个可能的解决方法是在将提供给Signature
类之前对进行重新编码以进行验证。
请注意,我不知道这可能是一个安全问题;签名由R和S的值组成,只要您最终收到正确的值,它们的编码方式无关紧要。