使用 salt 和迭代计数对消息进行哈希处理的正确方法?

Properly way to hash a message with salt and iteration count?

我需要使用随机盐和迭代计数对消息进行哈希处理。

这是我使用的方式(Way-1)

public static void main(String[] args) {

    byte[] message;
    byte[] randomSalt;
    int iterations = 1000;

    MessageDigest digest = MessageDigest.getInstance("SHA-256");

    byte[] hash = digest.digest(message);

    for (int i = 0; i < iterations; i++) {

        // randomSalt used multi-times
        hash = digest.digest(ArrayUtils.appendArrays(randomSalt, hash));
    }

    // Final result:  randomSalt + hash
}

然而,我发现了另一种人们使用的方式(Way-2)

public static void main(String[] args) {

    byte[] message;
    byte[] randomSalt;
    int iterations = 1000;

    MessageDigest digest = MessageDigest.getInstance("SHA-256");

    // Use randomSalt Once
    digest.update(randomSalt);

    byte[] hash = digest.digest(message);

    for (int i = 0; i < iterations; i++) {

        // randomSalt Are Not used here
        hash = digest.digest(hash);
    }

    // Final result:  randomSalt + hash
}

当然,两种方式产生不同的输出。

Way-1和Way-2的主要区别在于Way-1,salt是多次使用的。

问题: 你推荐哪种方式?谢谢!

None 个。

如果您要散列密码 以生成加密密钥,那么您应该使用可用的标准化方案,例如 PBKDF2、bcrypt、scrypt 或 Argon2。它们是专门为此目的而设计的。例如scrypt和Argon2会占用大量内存,无法通过ASIC实现破解加速。

如果您散列消息以进行身份​​验证,如MAC,那么您只需要散列两次。 HMAC 是这方面的标准化方案,例如,它可以防止单独使用底层哈希函数可能发生的长度扩展攻击。多次迭代不会增加安全性,除非 HMAC 密钥是低熵的(例如密码),在这种情况下,您需要使用基于密码的第一个建议派生出正确的密钥密钥推导函数。

如果您只需要一个完整性检查值,那么进行多次迭代是没有用的,消息的单个散列就足够了(它甚至不必加盐) . Integrity 没有安全目的,只能防止意外操作。另一方面,多次迭代通常用于减慢某些操作的速度,这不是完整性检查所需要的。如果您需要检测恶意操作,那么您 需要 使用 MAC,在 HMAC 的情况下,它只不过是一个键控哈希。

如果您需要消息的哈希值用于签名,那么多次迭代也不会提供额外的安全性。用于签名的哈希仅用于减小要签名的消息的大小。实际的签名安全性是由非对称算法而不是散列算法提供的,因此多次迭代不会在此处添加额外的安全性。如果签名算法被破坏,那么攻击者可以简单地创建一个被操纵消息的哈希值并对其进行签名。

这些只是散列函数的一些用途,但它们是最流行的。迭代哈希函数仅在 4 种情况中的 1 种情况下有用。