使用盐存储和验证散列密码

Store and validate hashed password with salt

我模拟存储密码哈希并在登录过程中对其进行验证。

我有一个名为 hashPassword(String password) 的方法来获取字符串密码,returns 它是添加盐的散列。

我选择 salt 作为静态值,在此示例中,我为密码选择相同的值 (hello123)

public class T1 {

public static void main(String[] args) {
    String userDefinedPassword = "hello123";
    String hashedPassToStoreInDB = String.valueOf(hashPassword(userDefinedPassword));
    System.out.println("what stores in DB: " + hashedPassToStoreInDB);
    // store in database

    //Password Verify
    String inputPassword = "hello123";
    String hashedInputPassword = String.valueOf(hashPassword(inputPassword));
    System.out.println("Users hashed password: " + hashedInputPassword);

    if (hashedPassToStoreInDB.equals(hashedInputPassword)) {
        System.out.println("Correct");
    } else {
        System.out.println("Incorrect");
    }
}

private static byte[] hashPassword(String password) {
    byte[] salt = new byte[16];
    byte[] hash = null;
    for (int i = 0; i < 16; i++) {
        salt[i] = (byte) i;
    }
    try {
        KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 128);
        SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        hash = f.generateSecret(spec).getEncoded();

    } catch (NoSuchAlgorithmException nsale) {
        nsale.printStackTrace();

    } catch (InvalidKeySpecException ikse) {
        ikse.printStackTrace();
    }
    return hash;
}
}

但结果是:

what stores in DB: [B@219c9a58
Users hashed password: [B@305918a5
Incorrect

为什么这两个值不一样?

我的代码有什么问题?

您正在生成 byte[] 数组的两个不同实例,其 String 表示遵循 Object.toString 中的表示。

因此,您的两个 byte[] 的哈希值不同。

尝试比较 Arrays.equals(yourSaltedPassword, yourOtherSaltedPassword)

例如:

byte[] foo = {1,2};
byte[] bar = {1,2};
System.out.println(foo == bar);
System.out.println(String.valueOf(foo).equals(String.valueOf(bar)));
System.out.println(Arrays.equals(foo, bar));

输出

false
false
true

如果您需要将 byte[] 存储为 String,您可以用 Arrays.toString(myByteArray) 等同地表示它们(对于相等的 byte[])。

两个相等密码之间的比较将 return 等于 Strings。

问题出在这里:

String hashedPassToStoreInDB = String.valueOf(hashPassword(userDefinedPassword));

这里:

String hashedInputPassword = String.valueOf(hashPassword(inputPassword));

您正在从 hashPassword 方法返回的 byte[] 创建一个 String,但使用了错误的方法。由于 String#valueOf 方法中没有 byte[] 的重载,它结束调用 String#valueOf(Object obj) 将在内部使用 Object#toString,数组本身的字符串表示是没有意义的。

改用new String(byte[] byteArray)

String hashedPassToStoreInDB = new String(hashPassword(userDefinedPassword));
//...
String hashedInputPassword = new String(hashPassword(inputPassword));

您无意中发现 java 数组不会覆盖 toString。

错误为什么要使用数组:您只需连接字符串,然后在结果上使用 hashCode() 即可获得基本的 salt:

int hash = (password + salt).hashCode();