没有盐的 sha-256 并不总是返回相同的哈希值

sha-256 without salt not always returning the same hash

谁能告诉我为什么下面的代码并不总是 return 相同的散列?据我所知,哈希值可能不同的唯一方法是随机盐,但根据文档,我通过将盐大小设置为 0 来禁用盐。

public static void main(String[] args ) {
    char[] password = "test_pass".toCharArray();
    String str = encodePassword(password);

    System.out.printf(
        "Byte digest '%s'\n", 
        String.valueOf(Hex.encodeHex(Base64.decodeBase64(str)))
    );
}

static StandardByteDigester digester = new StandardByteDigester();
{
    digester.setAlgorithm("SHA-256");
    digester.setIterations(100000);
    digester.setSaltSizeBytes(0);
    digester.initialize();
}

public static String encodePassword(char[] rawPass) {
    return new String(Base64.encodeBase64(digester.digest(toBytes(rawPass))));
}

public static byte[] toBytes(char[] ch) { 
    Charset charset = Charset.defaultCharset();
    ByteBuffer buff = charset.encode(CharBuffer.wrap(ch));
    byte[] tmp = new byte[buff.limit()];
    buff.get(tmp);
    return tmp;    
}

您的错误与您在 实例初始化程序块 而不是 静态初始化程序块 StandardByteDigester digester 中初始化静态字段 StandardByteDigester digester 有关=32=] 这样它就永远不会被调用,因为你永远不会创建你的 class 的实例所以 最后它使用默认配置 和随机盐。

试试这个:

static {
    digester.setAlgorithm("SHA-256");
    digester.setIterations(100000);
    digester.setSaltSizeBytes(0);
    digester.initialize();
}

如果您的方法 encodePassword 使用 String 而不是 char 数组,您的代码可以得到简化,因为您可以简单地调用 getBytes(Charset) 作为下一个:

public static String encodePassword(String rawPass) {
    return new String(
        Base64.encodeBase64(digester.digest(rawPass.getBytes(StandardCharsets.UTF_8))),
        StandardCharsets.US_ASCII
    );
}

注意: 依赖平台的默认字符集不是一个好的做法,因为您的代码将依赖于平台,所以这里因为 base 64 字符都包含在 US_ASCII,让我们使用这个字符集来解码。