使用salt和迭代计数散列消息的正确方法是什么?

时间:2016-06-28 19:22:51

标签: java hash cryptography salt

我需要使用随机salt和迭代计数来散列消息。

这是我使用的方式(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,盐多次使用。

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

1 个答案:

答案 0 :(得分:3)

他们都不是。

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

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

如果你只需要一个完整性检查值,那么进行多次迭代是没用的,并且消息的单个散列就足够了(它甚至不必被腌制)。完整性没有安全目的,只能防止意外操纵。另一方面,多次迭代通常用于减慢某些操作,这不是您想要的完整性检查。如果您需要检测恶意操纵,那么您需要使用MAC,这只不过是HMAC情况下的密钥哈希。

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

这些只是哈希函数的一些用法,但它们是最受欢迎的。迭代哈希函数仅在4种情况中的1种中有用。