12

我工作的组织使用 PPolicy(一个 OpenLDAP 模块)来自动加盐和散列密码。不幸的是,我无法访问运行 OpenLDAP 服务器的机器,所以我无法查看配置文件。从我所看到的情况来看,几乎所有内容似乎都是使用默认设置进行设置的。

我希望能够为特定用户检索盐。如果我查看用户的属性,userPassword 是 SSHA 密码。对于该特定用户,我没有看到任何关于盐的信息。我最终查看了 LDAP 模式,也没有看到任何关于盐的信息。

如果您要猜测每个用户的盐存储在哪里,它会在哪里?我知道这很模糊,可能信息不多,但是我在 OpenLDAP 文档中找不到任何地方来解释唯一盐的确切存储位置。也许以前配置过 OpenLDAP 服务器的人会知道默认位置在哪里。

谢谢你。

4

3 回答 3

22

使用 SSHA,通常将盐附加到 SHA1 哈希,然后整个内容是 Base64 编码的(我从未见过不以这种方式执行 SSHA 的 LDAP)。您应该能够通过查看 userPassword 属性来判断这一点。如果它是 28 个字符长,最后有一个 =,它只是散列。

如果 Base64 值的长度为 32 个字符或更大,则它包含哈希和盐。Base64 解码值并去掉前 20 个字节,这是 SHA1 哈希。剩余的字节是盐。

例子:

                     Base64 encoded hash with salt
userPassword: {SSHA}MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0

Base64 decoded value
     SHA1 Hash      Salt
--------------------++++
123456789012345678901234

编辑:经过仔细检查,似乎有时支持可变长度的盐。更正了编码描述以解决此问题。

于 2013-07-25T00:43:14.527 回答
3

Syon 的帖子对我帮助很大,谢谢!我认为对于在这个主题上苦苦挣扎的其他人来说,工作测试会是一个很好的补充;)。

public class SshaPasswordVerifyTest {
    private final static int SIZE_SHA1_HASH = 20;

    @Test
    public void itShouldVerifyPassword() throws Exception{
        String password = "YouNeverGuess!";
        String encodedPasswordWithSSHA = "{SSHA}M6HeeJAbwUCzuLwXbq00Fc3n3XcxFI8KjQkqeg==";
        Assert.assertEquals(encodedPasswordWithSSHA, getSshaDigestFor(password, getSalt(encodedPasswordWithSSHA)));
    }

    // The salt is the remaining part after the SHA1_hash
    private byte[] getSalt(String encodedPasswordWithSSHA){
        byte[] data = Base64.getMimeDecoder().decode(encodedPasswordWithSSHA.substring(6));
        return Arrays.copyOfRange(data, SIZE_SHA1_HASH, data.length);
    }

    private String getSshaDigestFor(String password, byte[] salt) throws Exception{
        // create a SHA1 digest of the password + salt
        MessageDigest crypt = MessageDigest.getInstance("SHA-1");
        crypt.reset();
        crypt.update(password.getBytes(Charset.forName("UTF-8")));
        crypt.update(salt);
        byte[] hash = crypt.digest();

        // concatenate the hash with the salt
        byte[] hashPlusSalt = new byte[hash.length + salt.length];
        System.arraycopy(hash, 0, hashPlusSalt, 0, hash.length);
        System.arraycopy(salt, 0, hashPlusSalt, hash.length, salt.length);

        // prepend the SSHA tag + base64 encode the result
        return "{SSHA}" + Base64.getEncoder().encodeToString(hashPlusSalt);
    }
}
于 2017-08-10T08:30:13.900 回答
0

在 PHP 中,这会将纯文本密码(通常由用户输入)与给定的 ssha 哈希(通常存储在您的数据库中)进行比较:

private function checkSshaPassword($encrypted_password, $password)
{
    //  get hash and salt from encrypted_password
    $base_64_hash_with_salt = substr($encrypted_password, 6);
    $hash_with_salt = base64_decode($base_64_hash_with_salt);
    $hash = substr($hash_with_salt, 0, 20);
    $salt = substr($hash_with_salt, 20);

    //  hash given password
    $hash_given = sha1($password . $salt, true);

    return ($hash == $hash_given);
}
于 2017-10-29T21:55:55.410 回答