【问题标题】:Java crypto API vs. different platformsJava 加密 API 与不同平台
【发布时间】:2011-07-16 20:23:14
【问题描述】:

我有一个 Android 应用程序,它使用 javax.crypto 加密文件中的一些文本数据。加密实现类似于this。该应用程序可以很好地处理它之前创建的加密数据。

现在,我几乎将我的 Android 应用程序移植到桌面 (JFace/SWT)。我对移植的应用程序使用相同的加密实现,因为它不依赖于任何 Android 特定的 API。移植的应用程序可以很好地处理它创建的加密数据。

问题是桌面应用程序无法解密使用 Android 应用程序保存的数据。 Android 应用程序无法解密数据,该数据也与桌面应用程序一起保存。我仔细检查了纯数据和密码的字节流,以便在两个平台上进行加密。它们是相同的,因此文本编码左右没有问题。但是加密程序在不同的平台上返回不同的加密结果,即使输入数据是字节到字节的。

Java 加密 API 是否保证在不同平台上进行相同的操作?加密提供程序(在我的情况下为 AES/128 位)是否应该在 Android、Linux 和 Windows 上以相同的方式工作?有没有办法调整javax.crypto 以获得在不同平台上的互操作性?

【问题讨论】:

  • 加密算法非常明确。如果输入逐字节相同,并且 Java 加密方法调用相同,则输出字节不应该有差异。
  • 如果您显示您用于加密/解密的代码,我们可能会显示问题点。
  • 你在指责 API,但我敢打赌这是你程序中的错误。
  • Paŭlo,如果您单击问题中的链接,您可以看到代码。实际代码与它非常相似。 GregS,我不是在责怪 API。目前,我发现不同的提供程序在 Android 和桌面上用于 AES 和 SHA1PRNG 算法。我看到在不同平台上为相同的密码生成了不同的安全密钥。我正在尝试将桌面应用程序切换到在 Android 上使用的提供程序。

标签: java interop cryptography


【解决方案1】:

AES-128 在两个系统上的工作方式应该相同。理论上。

在实践中,有很多细节需要在两个系统上保持相同。

  • 您是否在两侧使用相同的填充?
  • 双方是否使用相同的模式(CBC、CTR、ECB)?
  • 双方的密码是否完全相同
  • 两边的 IV/Nonce 是否相同?
  • 双方的密钥派生方法是否相同?

检查两个系统上的任何默认值。如果默认值不匹配,则需要明确设置一侧或另一侧。

【讨论】:

  • 感谢您的回答。我很高兴听到有机会使应用程序与彼此的加密数据一起工作。我将尝试查找有关所有这些 CBC、CTR、ECB、填充、IV/Nonce、推导以及如何使用javax.crypto 设置它们的信息。是的,我在双方都使用了相同的密码。我在两个系统上对密码字节流进行了三次检查。
  • 如果可以,请避免使用欧洲央行,因为它的安全性不高。至于密码,请检查双方是否使用相同的文本编码。例如,如果一侧是 UTF-8 而另一侧是 UTF-16,那么尽管密码可能看起来相同,但它们不会相同。
  • 重铸@rossum 明智建议的另一种方式是:永远不要依赖默认值。始终完全指定转换的所有方面。在编码/解码字符串时始终指定字符集,更好的是,始终使用 UTF-8。并且永远不要使用 String 作为随机字节的容器。
  • 我的桌面系统是Ubuntu,所以Android和桌面都使用UTF-8编码。但这没关系,因为我在加密前后检查了密码和数据的字节数组。有人知道如何获得 AES 算法的默认模式和填充吗?我需要它来保持向后兼容性。 cipher.getIV() 在两个系统上都返回“null”。
  • 终于成功了!感谢大家的想法!起初,我将桌面应用程序的 AES 提供程序更改为一个用于 Android(Bouncy Castle)的提供程序。这很容易,但并没有改变结果。接下来,我将 SHA1PRNG 实现更改为 Android 一(Apache Harmony)。这并不容易,但现在可以了!实际上,SHA1PRNG 的 SUN 和 Harmony 实现在相同的 secureRandom.setSeed(seed) 之后在 secureRandom.nextLong() 上返回不同的结果。
【解决方案2】:

依赖加密随机数生成器在不同平台上生成相同的随机数是错误的。通常,密钥派生算法中使用的加密随机盐必须从发送方传送到接收方。它可能会作为秘密传达,但确实需要传达。当然,“主密码”是主要秘密。

通常传达这些盐的一种方式是作为密文的前缀。这使得密文比明文长,但我认为这在您的示例技术中并不重要。

此外,对于完整的加密消息交换,需要将其他加密参数传递给解密器。您可以将它们连接到您的实现中,就像您在此处所做的那样,但取决于可重复性似乎太脆弱了。当然,攻击者可以复制它,所以它不是你的秘密。

您可能需要重新考虑密钥生成算法设置,使其更加稳健。

事后思考:在当前方法中发生的情况是,一种加密有用的 RNG 正在以一种已消除所有随机性的方式使用!检查 PBKDF2 和密钥派生的建议通常是一个很好的建议。

【讨论】:

  • 好点:PBKDF2 很好看这里需要什么。此外,W3C XML 加密规范将提供有关需要传达或连接到所有发送接收方的参数的线索。
  • 感谢您推荐使用 PBKDF2。我现在看到了 SHA1PRNG 的问题。但是,Android 目前似乎没有集成的 PBKDF2 实现。我得到了java.security.NoSuchAlgorithmException: SecureRandom PBKDF2 implementation not found
【解决方案3】:

您必须向我们展示一些代码。一个常见的初学者错误是将加密数据存储在 String 而不是它进来的 byte[] 中。String 不是二进制数据的容器。这种技术可能会在很多方面失败,包括默认的字谜差异。

【讨论】:

  • 感谢您的回答。如果您单击问题中的链接,您可以检查代码。实际代码与链接上的代码非常接近。
猜你喜欢
  • 2016-01-06
  • 2020-03-04
  • 1970-01-01
  • 2013-05-12
  • 2011-06-23
  • 2019-12-08
  • 2019-06-08
  • 1970-01-01
  • 2020-09-18
相关资源
最近更新 更多