问题 Java的MessageDigest SHA1算法返回的结果与php的SHA1函数不同


我有一个带有用户名和密码的SQL表。密码使用MessageDigest的digest()方法进行编码。如果我编码密码 - 让我们说“abcdef12” - 使用MessageDigest的digest()方法然后将其转换为十六进制值,则String与使用PHP的SHA1方法执行相同操作的情况不同。我希望这些值完全相同。

用于对密码进行编码的代码:

MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] passbyte;
passbyte = "abcdef12".getBytes("UTF-8");
passbyte = md.digest(passbyte);

使用此方法将String转换为十六进制:

public static String convertStringToHex(String str) {

    char[] chars = str.toCharArray();

    StringBuffer hex = new StringBuffer();
    for (int i = 0; i < chars.length; i++) {
        hex.append(Integer.toHexString((int) chars[i]));
    }

    return hex.toString();
}

密码: abcdef12

这是许多SHA1-hash在线生成器和PHP SHA1()函数返回的密码 - 函数: d253e3bd69ce1e7ce6074345fd5faa1a3c2e89ef

这是MessageDigest编码的密码: d253e3bd69ce1e7ce674345fd5faa1a3c2e2030ef

我忘了什么吗?

伊戈尔。

编辑:我发现有类似问题的人: C#SHA-1与PHP SHA-1 ...不同的结果? 。解决方案是更改编码..但我无法更改服务器端的编码,因为该SQL表中的密码不是由我的应用程序创建的。 我使用JavaScript SHA1类(更准确地说是一个Google Web Toolkit类)使用客户端SHA1编码。它按预期工作和编码字符串,但显然使用ASCII字符?..


11736
2017-09-30 01:54


起源



答案:


它与编码无关。输出将完全不同。

对于初学者,你的功能 convertStringToHex() 不输出前导零,即 07 变得公正 7

其余的(改变 89 至 2030)也可能与该功能有关。试着看看它的价值 passbyte 后 passbyte = md.digest(passbyte);


4
2017-09-30 02:15



谢谢!你的答案解决了我的问题。我没能正确地将字节数组转换为十六进制字符串!我使用了@stivlo的方法,效果很好!我打算将此回复标记为正确,但在这种情况下,我希望我可以将两个给定的回复标记为正确的回答!谢谢你们俩! - Igor


答案:


它与编码无关。输出将完全不同。

对于初学者,你的功能 convertStringToHex() 不输出前导零,即 07 变得公正 7

其余的(改变 89 至 2030)也可能与该功能有关。试着看看它的价值 passbyte 后 passbyte = md.digest(passbyte);


4
2017-09-30 02:15



谢谢!你的答案解决了我的问题。我没能正确地将字节数组转换为十六进制字符串!我使用了@stivlo的方法,效果很好!我打算将此回复标记为正确,但在这种情况下,我希望我可以将两个给定的回复标记为正确的回答!谢谢你们俩! - Igor


我使用Java SHA-1散列函数获得与PHP相同的摘要:

public static String computeSha1OfString(final String message) 
    throws UnsupportedOperationException, NullPointerException {
        try {
               return computeSha1OfByteArray(message.getBytes(("UTF-8")));
        } catch (UnsupportedEncodingException ex) {
                throw new UnsupportedOperationException(ex);
        }
}

private static String computeSha1OfByteArray(final byte[] message)
    throws UnsupportedOperationException {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(message);
            byte[] res = md.digest();
            return toHexString(res);
        } catch (NoSuchAlgorithmException ex) {
            throw new UnsupportedOperationException(ex);
        }
}

我已添加到我的单元测试中:

String sha1Hash = StringHelper.computeSha1OfString("abcdef12");
assertEquals("d253e3bd69ce1e7ce6074345fd5faa1a3c2e89ef", sha1Hash);

该类的完整源代码是 在github上


6
2017-09-30 02:01



确实 - 您的代码生成正确的SHA1(或者更确切地说:与php的SHA1相同)。但是,我正在编写一个必须登录到现有数据库的应用程序。该数据库不是由我自己创建的(也不是密码加密)。但 它使用我的示例中编写的MessageDigest 因此在该String上运行Base64.decode会返回不同的结果(在我的示例中指定的结果)而不是您正确的结果,我也使用该JavaScript SHA1类。有没有办法比较它们?我不知道MessageDigest如何返回其他结果。 - Igor


试试这个 - 它对我有用:

MessageDigest md = MessageDigest.getInstance(algorithm);
md.update(original.getBytes());
byte[] digest = md.digest();
StringBuffer sb = new StringBuffer();
for (byte b : digest) {
    sb.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();

问候, Konki


2
2017-12-27 09:22





或试试这个:

MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(clearPassword.getBytes("UTF-8"));
return new BigInteger(1 ,md.digest()).toString(16));

干杯罗伊


2
2017-08-26 14:27