Это процесс, который я прошел, чтобы понять это; Я напишу это полностью здесь, чтобы помочь вам изучить процесс, а не только это одно решение.
Из источника ShaPasswordEncoder
(комментарии для краткости удалены):
public class ShaPasswordEncoder extends MessageDigestPasswordEncoder {
public ShaPasswordEncoder() {
this(1);
}
public ShaPasswordEncoder(int strength) {
super("SHA-" + strength);
}
}
Выглядит для меня как довольно тонкий класс-фантик. Вызов new ShaPasswordEncoder(256)
фактически аналогичен вызову new MessageDigestPasswordEncoder("SHA-256")
, поэтому давайте посмотрим на источник для , который :
public class MessageDigestPasswordEncoder extends BaseDigestPasswordEncoder {
private final String algorithm;
private int iterations = 1;
[...]
public String encodePassword(String rawPass, Object salt) {
String saltedPass = mergePasswordAndSalt(rawPass, salt, false); /* 1 */
MessageDigest messageDigest = getMessageDigest();
byte[] digest = messageDigest.digest(Utf8.encode(saltedPass)); /* 2 */
// "stretch" the encoded value if configured to do so
for (int i = 1; i < this.iterations; i++) { /* 3 */
digest = messageDigest.digest(digest);
}
if (getEncodeHashAsBase64()) {
return Utf8.decode(Base64.encode(digest));
} else {
return new String(Hex.encode(digest)); /* 4 */
}
}
[...]
}
Ах, теперь мы куда-то добираемся. Там было несколько дополнительных методов, но пока мы действительно заботимся только о encodePassword
. Это работает примерно так, как вы ожидаете. Из пронумерованных строк:
- соль пароль
- При этом используется невинный метод
mergePasswordAndSalt
, который мы рассмотрим в следующем
- Hash соленый пароль
- Обратите внимание на кодировку UTF-8 здесь - это не всегда будет по умолчанию
- Неоднократно хэшируйте вывод для дополнительных итераций
- Обратите внимание, что как вход, так и выход метода
messageDigest.digest
являются необработанными байтовыми массивами, а не шестнадцатеричными строками
- Возвращает шестнадцатеричную строку конечного результата
Как и было обещано, вот источник mergePasswordAndSalt
метода:
protected String mergePasswordAndSalt(String password, Object salt, boolean strict) {
if (password == null) { /* 1 */
password = "";
}
if (strict && (salt != null)) { /* 2 */
if ((salt.toString().lastIndexOf("{") != -1)
|| (salt.toString().lastIndexOf("}") != -1)) {
throw new IllegalArgumentException("Cannot use { or } in salt.toString()");
}
}
if ((salt == null) || "".equals(salt)) {
return password;
} else {
return password + "{" + salt.toString() + "}"; /* 3 */
}
}
Опять из пронумерованных разделов:
- Проверить пустой пароль
- Проверить наличие символов
{
и }
; они не разрешены из-за следующего пункта
- Вывести соленый пароль в виде
password{salt}
Здесь мы видим, почему ваша попытка воспроизвести этот алгоритм в PHP не удалась.
Из этой информации узнайте, можете ли вы создать функцию PHP, которая ведет себя таким же образом. Сегодня вечером я отредактирую полное PHP-решение, когда у меня будет доступ к среде для его тестирования.