如何测试添加盐用于散列的有效性?

时间:2014-08-05 14:27:45

标签: hash salt

我对哈希很新,我使用SHA-256和自制的盐生成方法生成值的哈希值。它涉及确定性地为随机盐生成器的每个输入找到种子。现在我想验证哈希值的完整性,并检查添加的盐的有效性。但是,我不知道该怎么做。任何人都可以帮忙吗?

3 个答案:

答案 0 :(得分:1)

每个操作系统都有一个随机源并提供从该源获取随机字节的方法。大多数应用程序无法自己生成加密安全的盐,这就是他们从随机源读取的原因。测试此方法是在其他地方完成的,不需要在应用程序中测试这样的salt生成器,只需调用操作系统的方法。

答案 1 :(得分:0)

验证代码的正确性是Unit Testing的时间。

  

...一种软件测试方法,通过该方法测试各个源代码单元,一个或多个计算机程序模块的集合以及相关的控制数据,使用程序和操作程序,以确定它们是否适合使用。{ {3}}直观地,可以将单元视为应用程序中最小的可测试部分。

单元测试由测试框架辅助,框架可以检查您的代码库,查找标记为测试的任何内容并按需运行(即,当您告知它时)和/或自动作为构建或部署过程的一部分。我们的目标是获得某种程度的保证,即您对测试代码所做的更改不会破坏您的应用程序。测试应涵盖输入组合及其预期输出,从而强制执行行为。

热门测试框架包括用于Java的1,用于.Net语言的JUnitNUnit

无论如何,为了测试散列方案的完整性,您希望有一个封装所有行为的方法。您的单元测试将涵盖这一方法 1 。用Java JUnit语法编写它(使用匹配器,您可以看到更多关于many others的信息),我们可能会有这样的结果:

import org.junit.*;
public class PasswordSha256HasherTest {

    // Known inputs and outputs
    // hashes are precomputed with an external SHA256 calculator and verified
    public static final String password = "thisismypassword";
    public static final String unsaltedHash = "1da9133ab9dbd11d2937ec8d312e1e2569857059e73cc72df92e670928983ab5";
    public static final String salt = "a19044b439748e23ccbc82c5e2549ece5ceae026340ac6cb1f616549e64020e3";

    // This is what we want: SHA256(salt+password);
    public static final String saltedHash = "6c89a97409d598650e458a2040e900abbeca8e697137353fdaae97e382378433"

    // If your hasher has to be instantiated, do it like this
    private PasswordHasher hasher;

    @BeforeClass
    public static void beforeClass() throws Exception {
        hasher = new PasswordHasher();
    }

    @Test
    public void testCorrectPasswordHash() throws Exception {
        String hash = hasher.getPasswordHash(password, salt);
        // If PasswordHasher is a static class, you can skip the instantiation and do this
        String hash = PasswordHasher.getPasswordHash(password, salt);

        assertThat("Hash should match SHA256(salt + password)",
            hash, equalTo(saltedHash));
        // You could also test that the hash doesn't match the password or the salt
    }

    @Test(expected= IllegalArgumentException)
    public void testSaltIsRequired() throws Exception {
        // If the exception for an empty salt IS NOT thrown, this test fails.
        String hash = hasher.getPasswordHash(password, "");
    }

}

这只是一个开始,但这将完成您的问题的目标 - 验证哈希实用程序的完整性。您可以确定地编写许多其他测试(验证密码复杂性要求,禁止字典单词,盐长度要求等)。一些测试倡导者认为,编写有用且有意义的测试需要与设计代码本身一样多的思考和奉献。甚至还有测试驱动开发的理念,它指出你应该首先编写测试 (描述和封装代码的所有要求),并在所有测试通过后立即停止编写代码。这两者都有其优点。

如果您有兴趣向(可能)这个星球上的一些最好的测试人员学习,我也鼓励您查看here

最后,在相关的说明中,我想把我的观点告诉我们,盐应该是非确定性的并且是全球唯一的。实现此目标的最简单方法是使用足够大的伪随机值,该值与您的系统和用户完全无关,例如Google testing blogGUID解决了确切的主题,Security.SE上的This question也是如此。作为this question,如果您使用加密技术做自己的事情,那几乎肯定是错的。

1 :关于单元测试的适当范围存在争议。有人可能会说,登录系统最低有意义的工作单元是用户的创建和授权 - 具体来说,保护密码的机制只是授权模式其余部分的一部分,因此应该一起测试。对他们来说,我说分别测试每个部分会使查找和纠正特定错误的过程更容易,更直接。

答案 2 :(得分:0)

Martin说,你最好使用操作系统提供的伪随机值作为salt,从一个记录的适合加密用途的函数中使用。

另外,如果你想评估自己的盐常规,质量的标准是它应该产生大量可能的输出 - 具有从随机数得到的分组,分散和重复的水平,即使盐计算的输入只有一两个不同。它几乎与哈希函数的标准相同,但您可能不需要安全的东西来防止从salt值派生原始输入。

另外,如果您从用户的地址重新生成盐并且他们更改了它,您希望他们的当前密码用新盐重新计算哈希值,或者将旧盐或地址保存在某处以供持续使用...否则他们的下次登录尝试将注定失败。