我在 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()));
你在这里做的是:
- 将明文字符串转换为字节,使用系统默认编码
- 使用系统默认编码将 key 转换为字节
- 加密字节
- 使用系统的默认编码将加密的字节转换回字符串
- 使用系统默认编码将加密后的字符串转回字节
- 使用 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/