Меня озадачивает хэш-код (ASCII), хранящийся в Linux (Ubuntu) /etc/shadow.
Возьмем гипотетический случай, пусть пароль будет'тест', соль быть'Зем197Т4'.
Выполнив следующую команду,
$ mkpasswd -m SHA-512 test Zem197T4
Генерируется длинная серия символов ASCII (именно так Linux сохраняет данные в файле /etc/shadow)
$6$Zem197T4$oCUr0iMuvRJnMqk3FFi72KWuLAcKU.ydjfMvuXAHgpzNtijJFrGv80tifR1ySJWsb4sdPJqxzCLwUFkX6FKVZ0
При использовании онлайн-генератора SHA-512 (например,http://www.insidepro.com/hashes.php?lang=eng), то, что генерируется, представляет собой шестнадцатеричный код, как показано ниже:
вариант 1) пароль+соль
8d4b73598280019ef818e44eb4493c661b871bf758663d52907c762f649fe3355f698ccabb3b0c59e44f1f6db06ef4690c16a2682382617c6121925082613fe2
вариант 2) соль+пароль
b0197333c018b3b26856473296fcb8637c4f58ab7f4ee2d6868919162fa6a61c8ba93824019aa158e62ccf611c829026b168fc4bf90b2e6b63c0f617198006c2
Я считаю, что эти шестнадцатеричные коды должны быть 'тем же самым', что и коды ascii, сгенерированные mkpasswd. Но как они связаны?
Надеюсь, кто-нибудь сможет меня просветить?
решение1
В Ubuntu/Debian mkpasswd
является частью пакетактои реализовано в mkpasswd.c
котором на самом деле просто сложная оболочка вокруг crypt()
функции в glibc, объявленной в unistd.h
. crypt() принимает два аргумента пароль и соль. Пароль - это "test" в этом случае, соль предваряется "$6$" для хэша SHA-512 (см.SHA-крипт) поэтому «$6$Zem197T4» передается в crypt().
Возможно, вы заметили -R
опцию mkpasswd
which, которая определяет количество раундов. В документе вы найдете значение по умолчанию 5000 раундов. Это первый намек на то, почему результат никогда не будет равен простой конкатенации соли и пароля, он не хэшируется только один раз. На самом деле, если вы передадите, -R 5000
вы получите тот же результат. В этом случае "$6$rounds=5000$Zem197T4" передается в crypt(), а реализация в glibc (которая является libc Debian/Ubuntu) извлекает из этого метод и количество раундов.
То, что происходит внутри crypt(), сложнее, чем просто вычисление одного хеша, и результат в конце кодируется base64. Вот почему показанный вами результат содержит все виды символов после последнего '$', а не только [0-9a-f], как в типичной шестнадцатеричной строке хеша SHA-512. Алгоритм подробно описан в уже упомянутомSHA-криптдокумент.
решение2
Вся идея использования соленого пароля заключается в том, что каждый раз, когда вы генерируете хэш для одного и того же пароля, вы получаете другой результат. Это делается для того, чтобы избежать проблем с радужными таблицами.
Предположим, что один из ваших пользователей использует слабый пароль, скажем, 123456, ваш /etc/shadow был раскрыт. Теперь все, что нужно сделать злому хакеру, это использовать радужную таблицу, чтобы вычислить слабый пароль и использовать его снова в других местах.