Java和PHP中的SHA1生成结果不同

4

我知道有许多类似的问题,但是我在stackoverflow上尝试了每一个解决方案,但仍然没有得到预期的结果。

我正在尝试在Java和PHP中将字符串转换为sha1,但是我得到了不同的结果。该字符串是随机生成的。我在两端检查了字符串,它们是相同的(甚至尝试了在线比较工具)。

这是我在另一个应用程序中使用的相同代码,但在这种情况下不起作用。

我尝试用sha1散列的一个字符串是:UgJaDVYEClRUD1cAAVUBVwRTB1MDAA9SBgcDBwNXAwNZBQdUAAACBA==

Java结果:72c9bbe7eed0efe5e82ea9568136d8f52347259e

PHP结果:f720d73d18a7bb9cf36808af17ce40621ebfb405

Java代码

public static String sha1(String toHash)
{
    String hash = null;
    try
    {
        MessageDigest digest = MessageDigest.getInstance("SHA-1");
        byte[] bytes = toHash.getBytes("ASCII"); //I tried UTF-8, ISO-8859-1...
        digest.update(bytes, 0, bytes.length);
        bytes = digest.digest();
        StringBuilder sb = new StringBuilder();
        for(byte b : bytes)
        {
            sb.append(String.format("%02X", b));
        }
        hash = sb.toString();
    }
    catch(NoSuchAlgorithmException e)
    {
        e.printStackTrace();
    }
    catch(UnsupportedEncodingException e)
    {
        e.printStackTrace();
    }
    return hash.toLowerCase(Locale.ENGLISH);
}

PHP代码

sha1("UgJaDVYEClRUD1cAAVUBVwRTB1MDAA9SBgcDBwNXAwNZBQdUAAACBA==");

任何帮助都将不胜感激。 更新 在Java和PHP中,我正在执行以下操作: Java
String toHash = "qwerty";
String hash = sha1(toHash); //Prints: b1b3773a05c0ed0176787a4f1574ff0075f7521e

toHash = Base64.encodeToString(toHash.getBytes("ASCII"), Base64.DEFAULT);
hash = sha1(toHash); //Prints: 88bfb2d77c3b42823bab820c1737f03c97d87c1b

PHP

$toHash = "qwerty";
sha1($toHash); //Prints: b1b3773a05c0ed0176787a4f1574ff0075f7521e

sha1(base64_encode($toHash)); //Prints: 278aa0e8dde2af58a4eed613467da219a35c5278

我猜Base64编码在PHP和Java上对字符串的处理方式不同,你有什么想法吗?
更新2:
我应该表述得更清楚,抱歉。我的意思是:
Java输出的结果为:
sha1(Base64.encodeToString("qwerty".getBytes("ASCII"), Base64.DEFAULT));

PHP输出不同。

sha1(base64_encode("qwerty"));

更新3

虽然两个base64编码的字符串都相等cXdlcnR5

基本上:

- sha1("qwerty") == sha1("qwerty")
- Base64.encodeToString("qwerty".getBytes(), Base64.DEFAULT) == base64_encode("qwerty")
- sha1(Base64.encodeToString("qwerty".getBytes(), Base64.DEFAULT)) != sha1(base64_encode("qwerty"))

我已经在我哈希的字符串上取消了base64编码,但我仍然想知道我可以做什么来使它工作。


你的哈希值可能被不同地编码。例如,如果使用十六进制编码,你必须确保在 PHP 和 Java 上都这样做。 - DarkLeafyGreen
确保将字节数组正确转换为十六进制字符串。 - Blacklight
你在Base64 encodeToString函数中使用了两次toHash。我怀疑这不是你的意图。在Java中,你先对"qwerty"进行Base64编码,然后计算sha1值;而在PHP中,你却相反地进行。 - Lieven Keersmaekers
2个回答

4

编辑

您在encodeToString方法中两次使用了toHash变量,这使得您的第二行代码是多余的。

以下是代码:

String toHash = "qwerty";
String hash = sha1(toHash); //Prints: b1b3773a05c0ed0176787a4f1574ff0075f7521e

toHash = Base64.encodeToString(toHash.getBytes("ASCII"), Base64.DEFAULT);
hash = sha1(toHash); //Prints: 88bfb2d77c3b42823bab820c1737f03c97d87c1b

等价于这段代码
String toHash = "qwerty";
toHash = Base64.encodeToString(toHash.getBytes("ASCII"), Base64.DEFAULT);
hash = sha1(toHash); //Prints: 88bfb2d77c3b42823bab820c1737f03c97d87c1b

在Java中,你实际上是:

  • 获取“qwerty”的Base64编码
  • 在该结果上获取sha1哈希值

而在使用PHP时,你是:

  • 获取“qwerty”的sha1哈希值
  • 在该结果上获取Base64编码

我猜你打错了。


它打印出了正确的结果...这让我更加困惑问题出在哪里 :/ - Marco Batista
你自己尝试过了吗?这段代码与你的有什么区别?你用的是哪个Java版本(不像它很重要)? - Lieven Keersmaekers
是的,我做了,查看我刚刚进行的编辑以获取更详细的解释。 我正在使用Java 1.7.0_45-b18。 - Marco Batista
根据您最新的编辑,您说不匹配是在Base64编码中,而不是在sha1中?我建议您编辑您的问题或关闭此问题,并创建一个仅包含必要信息的新问题。SHA计算可以完全删除。 - Lieven Keersmaekers
我脑子里有太多事情了,经常忘记事情... 我的意思是在编辑中添加这个: Java的base64编码等于PHP的编码,两者都输出cXdlcnR5,基本上在sha1部分之前,PHP日志和Java日志都是同步的。sha1部分是日志开始出现差异的地方,因为两者都打印出不同的结果。 - Marco Batista
显示剩余2条评论

1

三年后,我遇到了同样的问题,但这一次我找到了问题所在。以下是解决方案,供遇到此问题的任何人参考:

我使用的是:

sha1("qwerty") == sha1("qwerty")
Base64.encodeToString("qwerty".getBytes(), Base64.DEFAULT) == base64_encode("qwerty")
sha1(Base64.encodeToString("qwerty".getBytes(), Base64.DEFAULT)) != sha1(base64_encode("qwerty"))

这个问题在于Base64.DEFAULT,Base64的默认行为是将字符串换行(在字符串中添加\n)。 为了获得与PHP方法相同的结果,您应该使用Base64.NO_WRAP
sha1("qwerty") == sha1("qwerty")
Base64.encodeToString("qwerty".getBytes(), Base64.NO_WRAP) == base64_encode("qwerty")
sha1(Base64.encodeToString("qwerty".getBytes(), Base64.NO_WRAP)) == sha1(base64_encode("qwerty"))

我做了这个更改之后,它开始工作了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接