Как получить соль из LDAP?
В организации, в которой я работаю, используется PPolicy (модуль OpenLDAP) для автоматического солевого и хеш-паролей. К сожалению, у меня нет доступа к машине, на которой запущен сервер OpenLDAP, поэтому я не могу посмотреть на файл конфигурации. Из того, что я видел, почти все, кажется, настраивается с использованием настроек по умолчанию.
Я хотел бы получить соль для конкретного пользователя. Если я смотрю на пользовательские атрибуты, userPassword является паролем SSHA. Я ничего не вижу о соли для этого конкретного пользователя. Я закончил поиск схемы LDAP, и я ничего не вижу о сотах.
Если бы вы догадались, где соль хранится для каждого пользователя, где это будет? Я понимаю, что это неопределенное и, вероятно, не много информации, но я не могу найти нигде в документах OpenLDAP, которые объясняют, где хранятся уникальные соли. Возможно, кто-то, кто настроил сервер OpenLDAP раньше, будет знать, где находится местоположение по умолчанию.
Спасибо.
Ответы
Ответ 1
С SSHA обычно соль добавляется к хэшу SHA1, а затем все кодируется Base64 (я никогда не видел LDAP, который не делал SSHA таким образом). Вы должны быть в состоянии сказать это, посмотрев атрибут userPassword. Если он длиной 28 символов с a = в конце, это только хэш.
Если значение Base64 равно 32 символам в длину или больше, оно содержит как хэш, так и соль. Base64 декодирует значение и удаляет первые 20 байтов, это хэш SHA1. Остальные байты являются солью.
Пример:
Base64 encoded hash with salt
userPassword: {SSHA}MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0
Base64 decoded value
SHA1 Hash Salt
--------------------++++
123456789012345678901234
Edit: после двойной проверки кажется, что соли переменной длины иногда поддерживаются. Исправлено описание кодировки для учетной записи.
Ответ 2
Должность 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);
}
}
Ответ 3
В PHP это сравнивает обычный текстовый пароль (обычно вводимый пользователем) с заданным хэш-кодом ssha (обычно хранящимся в вашем db):
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);
}