Создание тех же хешей, которые symfony2 делает с Java (SHA-512)

У меня есть старое приложение на основе Symfony2, и я разрабатываю замену Dropwizard на Java.
Я перенес все пользовательские записи из старой БД в мою новую модель данных.
Я также добавил новые поля для паролей и импортировал старые поля паролей и соли.

Теперь я хочу сделать хорошо известную процедуру. Позвольте пользователю войти в систему, попробуйте ввести новое поле пароля. Если это не удается, попробуйте перенастроенные, если они работают, закодируйте пароль в виде открытого текста с новым алгоритмом и сохраните новый хеш в поле нового пароля. Так что пользователи переносят туда хеши паролей от старой процедуры к новой.

Звучит просто и нормально, это работает как обычно, но этот Symfony и PHP сводят меня с ума.

Я застрял в том же хеше с Java, что и Symfony.
Старое приложение использует MessageDigestPasswordEncoder с «sha512», кодировкой base64 и 5000 итераций, все по умолчанию;)

Важными методами являются:

MessageDigestPasswordEncoder:

public function encodePassword($raw, $salt) {
if ($this->isPasswordTooLong($raw)) {
throw new BadCredentialsException('Invalid password.');
}

if (!in_array($this->algorithm, hash_algos(), true)) {
throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
}

$salted = $this->mergePasswordAndSalt($raw, $salt);
$digest = hash($this->algorithm, $salted, true);

// "stretch" hash
for ($i = 1; $i < $this->iterations; ++$i) {
$digest = hash($this->algorithm, $digest.$salted, true);
}

return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
}

И BasePasswordEncoder:

protected function mergePasswordAndSalt($password, $salt) {
if (empty($salt)) {
return $password;
}

if (false !== strrpos($salt, '{') || false !== strrpos($salt, '}')) {
throw new \InvalidArgumentException('Cannot use { or } in salt.');
}

return $password.'{'.$salt.'}';
}

Это кажется прямым, но я застрял с этим.
Когда я читаю это, это делает:

  1. Объединить соль и открытый текстовый пароль с: «пароль {соль}»
  2. Хешируйте эту строку с SHA-512 и возвращайте двоичную строку в переменную дайджеста
  3. повторить 5k раз и использовать дайджест, соединенный паролем открытого текста, чтобы перефразировать в дайджест
  4. закодировать дайджест в base64

Итак, вот моя попытка в Java:

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

public void legacyEncryption(String salt, String clearPassword) throws UnsupportedEncodingException, NoSuchAlgorithmException {
// Get digester instance for algorithm "SHA-512" using BounceCastle
MessageDigest digester = MessageDigest.getInstance("SHA-512", new BouncyCastleProvider());

// Create salted password string
String mergedPasswordAndSalt = clearPassword + "{" + salt + "}";

// First time hash the input string by using UTF-8 encoded bytes.
byte[] hash = digester.digest(mergedPasswordAndSalt.getBytes("UTF-8"));

// Loop 5k times
for (int i = 0; i < 5000; i++) {
// Concatenate the hash bytes with the clearPassword bytes and rehash
hash = digester.digest(ArrayUtils.addAll(hash, mergedPasswordAndSalt.getBytes("UTF-8")));
}

// Log the resulting hash as base64 String
logger.info("Legace password digest: salt=" + salt + " hash=" + Base64.getEncoder().encodeToString(hash));
}

Кто-нибудь видит проблему? Я думаю, что разница в результате:
PHP: двоичный.
и
JAVA: addAll (byte [], byte [])

заранее спасибо

4

Решение

Реализация на стороне php правильно делает 5 000 итераций, выполняя первый раунд хэширования, а затем цикл 4999 раз.

$digest = hash($this->algorithm, $salted, true);

for ($i = 1; $i < $this->iterations; ++$i) {
$digest = hash($this->algorithm, $digest.$salted, true);
}

В реализации Java цикл for начинается с 0, что приводит к 5k + 1 итерации.

При запуске цикла for в 1 также в java результирующие хеши паролей равны.

byte[] hash = digester.digest(mergedPasswordAndSalt.getBytes("UTF-8"));

for (int i = 0; i < 5000; i++) {
hash = digester.digest(ArrayUtils.addAll(hash, mergedPasswordAndSalt.getBytes("UTF-8")));
}
4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]