9

我正在开发一个 Android 应用程序,我需要使用javaSignature进行数据认证。

在每台 Android 设备上,我都可以对数据进行签名并验证其签名。但是,给定要签名的明确数据块、明确的模数、明确的私有指数和明确的公共指数,我的签名输出是不同的,具体取决于设备。我确实尝试了一堆设备,我获得了 Android 3.2 和 3.2.1 的相同签名,但对于 Android 2.2.x 设备却不同。

我从之前KeyFactory在 java 项目中使用 RSA 生成的常量字段计算这些签名。密钥大小为 2048 位。

这是我用来调用签名和验证的代码的引用。

public byte[] signData(byte[] data, PrivateKey privateKey) throws ... {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data);
        return signature.sign();
}

public boolean verifyData(byte[] data, byte[] sigBytes, PublicKey publicKey) throws ... {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(publicKey);
        signature.update(data);
        return signature.verify(sigBytes);
}

如果我没记错的话,使用带有 RSA 的 SHA256 的签名是确定性的。那么我该如何解释这种行为呢?另一个有趣的问题,我怎样才能让它跨设备工作,即签名是一样的,不管我使用哪个设备?

提前谢谢你,弗兰克!

4

1 回答 1

12

是的,SHA256withRSA是完全确定的。

从理论上讲,您可能会受到其中一个 Android 版本上的旧修改 BouncyCastle 库版本中的错误(参见示例)的影响。SHA512withRSA如果您改为使用这样的错误,那么至少引用的错误可能会被消除。

但是,在您开始深入研究哈希算法之前,请在家附近进行检查。

也许您已经通过调用String.getBytes. 此调用取决于Android 2.2 和 Android 2.3 之间不同的默认平台编码。这意味着虽然您的字符串在两种情况下都相同,但字节数组可能不同。

要控制编码并使您的代码平台独立,请将编码指定为参数:

plainText.getBytes("UTF-8")

如果做不到这一点,还有更多的策略来获得独立于平台的实现。

  • 等到 2.2 与大概有缺陷的库消失
  • 随您的软件分发一个已知良好的库 (jar)。如果那将是 BouncyCastle,您将无法确保加载您而非 Android 的类。该解决方案称为 SpongyCastle。
  • 玩对齐/填充。通过添加您自己的固定填充,尝试使消息长度(以字节为单位)与 0、55、56 或 63 模 64 一致,并希望这些选项之一将开始提供可移植签名。选择这些值是为了与可疑算法的最外层部分交互,该部分填充到 512 位块。
于 2012-06-28T21:14:53.710 回答