java - 为什么 Java 和 PHP 中的 Blowfish 输出仅相差 2 个字符?

标签 java php encryption interop blowfish

我在 PHP 和 JAVA 中有一个河豚加密脚本,反之亦然,直到今天我遇到问题时它都运行良好。

相同的内容在 Java 和 PHP 中仅通过 2 个字符进行不同的加密,这真的很奇怪。

PHP

wTHzxfxLHdMm/JMFnoh0hciS/JADvFFg

Java

wTHzxfxLHdMm/JMFnoh0hciS/D8DvFFg
-------------------------^^

如您所见,这两个位置不匹配。不幸的是,该值是一个真实的电子邮件地址,我无法共享。此外,我无法用我测试过的其他几个值重现该问题。我试过更改 Java 上的 Base64 编码类,但都没有帮助。

PHP is here 的源代码, 以及 Java is here .

我该怎么做才能解决这个问题?

最佳答案

让我们看看您的 Java 代码:

String c = new String(Test.encrypt((new String("thevalue")).getBytes(),
                                   (new String("mykey")).getBytes()));
...
System.out.println("Base64 encoded String:" +
                   new sun.misc.BASE64Encoder().encode(c.getBytes()));

你在这里做的是:

  1. 将明文字符串转换为字节,使用系统默认编码
  2. 使用系统默认编码将 key 转换为字节
  3. 加密字节
  4. 使用系统的默认编码将加密的字节转换回字符串
  5. 使用系统默认编码将加密后的字符串转回字节
  6. 使用 Base64 对这些加密字节进行编码。

问题出在第 4 步。它假定任意字节数组代表系统默认编码中的字符串,并且对该字符串进行编码返回相同的 byte[]。这对某些编码有效(例如 ISO-8859 系列),但对其他编码无效。在 Java 中,当某些字节(或字节序列)在给定的编码中无法表示时,它将被一些其他字符替换,稍后为了重新转换将映射到字节 63(ASCII ?)。实际上,文档甚至说:

The behavior of this constructor when the given bytes are not valid in the default charset is unspecified.

在您的情况下,根本没有理由这样做 - 只需使用您的 encrypt 方法直接输出的字节将它们转换为 Base64。

byte[] encrypted = Test.encrypt("thevalue".getBytes(),
                                "mykey".getBytes());
System.out.println("Base64 encoded String:"+ new sun.misc.BASE64Encoder().encode(encrypted));

(另请注意,我在这里删除了多余的 new String("...") 构造函数调用,尽管这与您的问题无关。)

要记住的要点:永远不要将不是来自编码字符串的任意字节[]转换为字符串。加密算法的输出(以及大多数其他加密算法,除了解密)当然属于不应转换为字符串的数据类别。

如果你想要可移植的程序,永远不要使用系统的默认编码。

关于java - 为什么 Java 和 PHP 中的 Blowfish 输出仅相差 2 个字符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6759650/

相关文章:

java - 如何根据变量填充多维数组

java - C# 中的 Point2D.Double

javascript - 获取 API 请求的输出(客户端)

php - 无法更改 DATETIME 格式

php - 将 cookie curl 到 Golang HTTP 请求

javascript - TypeScript 中的 RSA 加密/解密

c# - java 和 Wp7 中的压缩和加密不匹配

java - 脱离上下文编译 Java 文件

java - 游戏结束后重新开始游戏

encryption - 如何解密 Telegram 网络请求