【问题标题】:Android password hashAndroid密码哈希
【发布时间】:2021-10-12 12:32:10
【问题描述】:

我在 PHP 中使用这段代码来加密密码:

return sha1("kD0a1".md5("xA4".$password)."f4A");

有人知道在 Android 中使用的有效替代品吗?我为 MD5 和 SHA1 尝试了不同的函数,但在 Java 中它总是生成与 PHP 不同的 HASH。

例如如下:

    public static String passwordHash(String password) {
        return sha1("kD0a1"+md5("xA4"+password)+"f4A");
    }

    public static String md5(String s) {
        try {
            MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
            digest.update(s.getBytes());
            byte messageDigest[] = digest.digest();

            StringBuffer hexString = new StringBuffer();
            for (int i=0; i<messageDigest.length; i++)
                hexString.append(Integer.toHexString(0xFF & messageDigest[i]));

            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    public static String sha1(String clearString) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
            messageDigest.update(clearString.getBytes("UTF-8"));
            byte[] bytes = messageDigest.digest();
            StringBuilder buffer = new StringBuilder();
            for (byte b : bytes) {
                buffer.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
            }
            return buffer.toString();
        }
        catch (Exception ignored) {
            ignored.printStackTrace();
            return null;
        }
    }

但是,PHP 和 Java 会返回一个不同的 HASH 字符串给我。

PASS: test
PHP: 17bf2c08f4b9447cf8316736e13833316d3edc23
JAVA: 8434696e252b89af0db033eb255c88a91a42ce14

但是,例如,如果我输入“passTest”,它将正确生成哈希

PASS: passTest
PHP: db4aedf1d4072b7b645996394aa74743f14eeb7a
JAVA: db4aedf1d4072b7b645996394aa74743f14eeb7a

而“passwordTest”又错了。

PASS: passwordTest
PHP: 1ad47c24d556187f1de5db66ff623bbe08a27f33
JAVA: 0f058b3aea48e69c028a7ee2693a98d6074b10a8

我无法解释它有时有效,有时无效,同时它只是更改密码的字符串。

您认为编码或其他方面可能存在问题吗?我以为是 TextView 做的,但即使我在 TextView 之外输入一个字符串,它的行为也是一样的。

提前感谢您的任何建议。

我要补充一点,我正在 SDK 31 上进行测试

M.

【问题讨论】:

  • 确保在调用 getBytes 时使用相同的编码,例如getBytes("UTF-8"); 并在 PHP 中使用相同的字符编码。你不是用 MD5 做的
  • “我在 PHP 中使用这段代码来加密密码”——它不加密密码。它使用不安全的哈希函数使用固定的盐对其进行两次哈希处理。 “我为 MD5 和 SHA1 尝试了不同的函数,但在 Java 中它总是生成与 PHP 不同的 HASH”——也许你应该一次只看一个。首先让你的 MD5 哈希匹配,没有盐。然后,将盐添加到您的 MD5 哈希中。然后,获取一个简单字符串的 SHA-1 哈希匹配。然后,为您的盐渍 MD5 输出获取您的 SHA-1 哈希匹配。以此类推。
  • 然后然后使用正确的密码散列算法。
  • 但是,正如 luk2302 所建议的那样,研究适当的密码散列算法(由安全专家创建的算法(scrypt、bcrypt、Argon2 等)并使用其中一种算法)可能会更好。跨度>
  • 是的,你说得对,我忘了。对于 MD5,我将“md.digest()”替换为“md.digest (md5.getBytes("UTF-8"))”,现在它可以正常工作了。到目前为止,所有测试都通过了 100%,所以希望一切都会好起来的。再次感谢您的帮助。

标签: java android md5 sha1


【解决方案1】:

下面的代码可以帮助你实现你想要的,它是一个名为 hashing 和 salt password 的方法,此外,salt 方法可以防止已经在你的数据库中注册的密码冲突

 public static String hashPassword(String password) throws NoSuchAlgorithmException {
        
        MessageDigest md = MessageDigest.getInstance("SHA-512");
        md.reset();
        md.update(password.getBytes());
        byte[] mdArray = md.digest();
        StringBuilder sb = new StringBuilder(mdArray.length * 2);
        for(byte b : mdArray) {
            int v = b & 0xff;
            if(v < 16)
                sb.append('0');
            sb.append(Integer.toHexString(v));
        }
        
        
        
        return sb.toString();
        
    }

这里是盐法

public static String getSalt() throws NoSuchAlgorithmException {
    SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
    byte[] salt = new byte[32];
    sr.nextBytes(salt);
    return Base64.getEncoder().encodeToString(salt);
    
}

如需进一步了解不同的哈希和加盐密码,请参阅以下链接,它可能会帮助您巩固您的理解

https://howtodoinjava.com/java/java-security/how-to-generate-secure-password-hash-md5-sha-pbkdf2-bcrypt-examples/

注意:您应该使用强大的实现来散列您的密码以防止破解

【讨论】: