调用PGPOnePassSignature.verify时签名长度不正确

5
我们正在使用一个名为license3j的Java库进行许可证管理。该库使用非对称加密,并依赖于Bouncycastle。我们使用简单的gpg命令创建许可证文件,并在我们的软件中使用公钥验证许可证。到目前为止,一切都运行良好。但是,在生成的1,000个许可证中,有很小一部分无法正确验证,尽管它们实际上是有效的(大约5/1000)。
在这种情况下会发生什么:当要在com.verhas.licensor.License.setLicenseEncoded(InputStream)中验证许可证时,org.bouncycastle.openpgp.PGPOnePassSignature.verify(PGPSignature)会抛出以下异常:

org.bouncycastle.openpgp.PGPRuntimeOperationException: 无法验证签名:签名长度不正确:得到了511但期望是512

对于我只有基本密码学知识的人来说,这听起来相当晦涩。经过几个小时的谷歌搜索,我想到了“前导零”的问题。所以,在这个例子中,显然某个地方(哪里?)削减了一个前导零,并且要比较的签名数据长度不匹配。很有道理。

现在,我不知道问题可能在哪里。是在许可文件的创建过程中出现的吗?基本上,我们只需执行以下操作:

gpg --armor --local-user=name.of.software --sign

这将为我们提供许可文件。

或者错误发生在验证期间?我是否需要修改任何Bouncycastle配置以正确解决前导零问题?他们的FAQ给出了一些提示,但是License3jsource显然从未使用过任何Cipher实例,因此我完全不知道如何将其集成到给定的API中。

我知道这是一个非常特殊的问题,涉及到一个显然不太知名的库。因此,我感激任何小的反馈或输入。

1个回答

6
看起来这是bouncycastle中的一个错误,只在Java 1.6之后的版本中遇到过。bouncycastle一直以来都会错误地创建数据,但自从Java 1.7以来,Java在验证期间接受的数据变得更加严格了。
当bouncycastle将签名序列化到文件时,它未能正确填充签名的长度,如果整数有足够多的前导零,则其字节表示将更小。Java 1.7及以上版本期望RSA签名字节与密钥相同长度。
bouncycastle将Java的RSA JCE提供程序返回的RSA签名字节数组转换为整数,并丢弃其长度信息。 PGPSignatureGenerator的第263行 显示了RSA签名字节从JCE返回并转换为整数的位置。
这个整数最终使用MPInteger#encode写入输出流,该方法仅使用基础大整数的位长度来确定要写入多少数据。 这篇答案更多地描述了为什么你会在大约200个案例中看到这个近似值以及Java版本如何发挥作用。

谢谢Magnus,这真的帮助我理解了问题!你有什么建议吗?我怎样才能以可控的努力来解决这个问题?浏览BC源代码并没有发现任何可以插入操作的点。还有其他的替代方法吗? - qqilihq
2
不幸的是,在bouncycastle中修复它似乎并不容易,您可以尝试在其问题跟踪器中提出错误报告,但我不确定您会有多少成功。一个hacky的解决方法可能是尝试验证每个许可证,并在失败时重新生成它。 - Magnus
其实我也考虑过重新生成许可证的想法,但我们生成许可证的服务器并不运行在Java环境中。为了验证许可证而设置JRE将是一件非常麻烦的事情。我会尝试在BC提出这个问题。还有一个问题:除了BC之外,是否还有其他加密库,或者现在是否可以使用Java API中的类来执行GPG签名的验证?毕竟,有一个java.security.Signature类。验证步骤似乎并不太复杂,所以我也考虑重新编写该功能。 - qqilihq
2
我不相信还有其他免费的Java库可以执行PGP。实际的RSA签名验证是由Java标准库处理的,这就是为什么在1.7中行为发生了变化。如果你想修改license3j,你可能可以通过包装验证器提供程序来添加一些填充,但我不确定它是否会起作用。https://gist.github.com/magJ/27b2909ce749da6dd0ea19a3eb334a53 - Magnus
很酷,一旦我找到更多的空闲时间,我会去看看!谢谢!! - qqilihq

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接