如何从LDAP检索salt?

时间:2013-07-18 20:15:00

标签: sha1 salt openldap ssha

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

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

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

谢谢。

3 个答案:

答案 0 :(得分:17)

使用SSHA,通常将salt附加到SHA1哈希,然后整个事务是Base64编码(我从未见过没有以这种方式执行SSHA的LDAP)。您应该能够通过查看userPassword属性来说明这一点。如果它的长度为28个字符,最后一个=,那么它只是哈希值。

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

示例:

                     Base64 encoded hash with salt
userPassword: {SSHA}MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0

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

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

答案 1 :(得分:0)

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);
    }
}

答案 2 :(得分: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);
}