13

我在 PHP 和 JAVA 中有一个河豚加密脚本,反之亦然,直到今天我遇到问题时它都可以正常工作。

相同的内容在 Java 和 PHP 中的加密方式不同,只有 2 个字符,这真的很奇怪。

PHP

wTHzxfxLHdMm/JMFnoh0hciS/JADvFFg

爪哇

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

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

PHP的源代码在这里Java 的源代码在这里

我能做些什么来解决这个问题?

4

3 回答 3

8

让我们看一下您的 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. 使用系统的默认编码将密钥转换为字节
  3. 加密字节
  4. 使用系统的默认编码将加密的字节转换回字符串
  5. 使用系统的默认编码将加密的字符串转换回字节
  6. 使用 Base64 对这些加密字节进行编码。

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

当给定字节在默认字符集中无效时,此构造函数的行为未指定。

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

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

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

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

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

于 2011-08-20T16:37:50.447 回答
0

你的代码对我来说似乎是正确的。

看起来您在这些程序之一的输入中有一个尾随空格,它只是一个。我会告诉你为什么:

这些 4 字符块中的每一个都代表加密字符串中的 3 个字符。不同的部分(第 7 块中的 JA 和 D8)实际上来自一个不同的字符。

wTHz xfxL HdMm /JMF noh0 hciS /JAD vFFg

wTHz xfxL HdMm /JMF noh0 hciS /D8D vFFg

如果我没看错,您的电子邮件地址长度为 19 个字符。您的一个输入字符串中的第 20 个字符是一个空格。

于 2011-07-21T03:10:28.303 回答
0

问题:您是否尝试过相关的PHP解密库来解密PHP生成的密文?你试过相关的JAVA解密库来解密JAVA密文吗?

如果两者都产生不同的输出,那么其中一个必须解密失败。

那是一个PHP还是Java?

无论是哪一个——我都会尝试用一个可公开共享的字符串来复制另一个这样的失败......将该字符串作为单元测试提供给开发人员或开发人员,这些开发人员使用该轮的语言创建加密/解密代码——行程加密/解密失败。

然后……等他们修好。

不确定是否有任何更快的解决方案——除了可能更改加密/解密库提供程序......或者自己动手......

于 2011-08-12T02:06:30.917 回答