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

Signature length not correct when calling PGPOnePassSignature.verify

我们正在使用一个名为 license3j 的 Java 库来管理许可证。该库使用非对称加密并依赖于 Bouncycastle。我们使用简单的 gpg 命令创建许可证文件,并使用我们的 public 密钥在我们的软件中验证许可证。到目前为止一切正常。但是:在 1,000 个生成的许可证中,有一小部分无法正确验证,尽管它们实际上是有效的(大约 5/1000)。

在这种情况下会发生什么:当要在 com.verhas.licensor.License.setLicenseEncoded(InputStream), the org.bouncycastle.openpgp.PGPOnePassSignature.verify(PGPSignature) 中验证许可证时抛出以下异常:

org.bouncycastle.openpgp.PGPRuntimeOperationException: unable to verify signature: Signature length not correct: got 511 but was expecting 512

对我来说听起来很晦涩,只有基本的密码学知识。花几个小时谷歌搜索,给了我线索,"leading zeros" 有一些东西。因此,在给定的示例中,显然前导零在某处(哪里?)被剥离,并且要比较的签名数据的长度不匹配。有道理。

现在,我不知道问题出在哪里。是在创建 许可证文件期间吗?本质上,我们只是在做以下事情:

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

这会给我们许可证文件。

或者是在验证的过程中发生错误?我是否必须修改任何 Bouncycastle 配置才能正确解决前导零问题?他们的 FAQ gives some hints, but the License3j source 显然从不使用任何 Cipher 实例,所以我完全不知道如何将它集成到给定的 API.

我知道这是一个非常特殊的问题,对于一个显然不是很出名的库来说。因此,我感谢任何反馈或意见。

貌似是bouncycastle的bug,只在Java1.6以后的版本遇到过,bouncycastle一直创建数据错误,但是Java 从 1.7 开始,它在 验证 期间接受的数据变得更加严格。

Bouncycastle 在将签名序列化到文件时未能将签名填充到正确的长度,如果整数有足够多的前导零,那么它的字节表示将会更小。
Java 版本 1.7 及更高版本要求 RSA 签名字节与密钥的长度相同。

Bouncycastle 将 RSA 签名字节数组(从 Java 的 RSA JCE 提供程序返回)转换为整数并丢弃有关其长度的信息。
Line 263 of the PGPSignatureGenerator 显示 RSA 签名字节从 JCE 返回并转换为整数的位置。

此整数最终使用 MPInteger#encode 写入输出流,它仅使用底层 biginteger 的位长来确定要写入的数据量。

This answer 详细说明了为什么您在每 200 个案例中看到一个近似值,以及 Java 的版本如何发挥作用。