crypt
(PHP 4, PHP 5)
crypt — Необратимое хэширование строки
Описание
$str
[, string $salt
] )crypt() возвращает хэшированную строку, полученную с помощью стандартного алгоритма UNIX, основанного на DES, или другого алгоритма, имеющегося в системе.
Некоторые операционные системы поддерживают несколько алгоритмов
хэширования. Иногда стандартный алгоритм, основанный на DES,
заменяется алгоритмом на основе MD5. Вид хэширования определяется
переданным аргументом salt (соль). До версии PHP 5.3, PHP определял
доступные алгоритмы шифрования во время инсталляции, базируясь
на системной функции crypt(). Если соль не указана,
будет автоматически сгенерирована стандартная случайная
двухсимвольная (DES) либо двенадцатисимвольная (MD5) соль, в
зависимости от доступности алгоритма MD5 в crypt().
Предопределенная константа CRYPT_SALT_LENGTH
позволяет определить максимально доступную длину соли в
соответствии с используемыми алгоритмами.
Стандартная функция crypt() на основе DES копирует
возвращает соль в качестве первых двух символов возвращаемой
строки. Кроме того, она использует только первые восемь символов
строки str
, поэтому более длинные строки,
начинающиеся с тех же восьми символов, сгенерируют один и тот же
результат (при использовании одинаковой соли).
На системах, где функция crypt() поддерживает несколько алгоритмов хэширования, следующие константы устанавливаются в 0 или 1 в зависимости от доступности соответствующего алгоритма:
-
CRYPT_STD_DES
- Стандартное DES-шифрование с двухсимвольной солью из алфавита "./0-9A-Za-z""./0-9A-Za-z". Использование других символов в соли повлечет за собой отказ работы crypt(). -
CRYPT_EXT_DES
- Расширенное DES-шифрование. "Соль" является девятисимвольной строкой, состоящей из символа подчеркивания, за которым следуют 4 байта счетчика итерации и 4 байта соли. Эти данные будут закодированы в виде печатаемых символов, 6 бит на символ, с меньшим значащим символом указанным первым. Значения от 0 до 63 кодируются как "./0-9A-Za-z". Использование других символов в соли повлечет за собой отказ работы crypt(). -
CRYPT_MD5
- MD5-шифрование с 12-символьной солью, начинающейся с $1$ -
CRYPT_BLOWFISH
- Blowfish-шифрование со следующей солью: "$2a$", весовой параметр из двух цифр, "$" и 22 цифры из алфавита "./0-9A-Za-z". Использование других символов в соли повлечет за собой возвращение пустой строки. Весовой параметр из двух цифр является двоичным логарифмом счетчика итераций низлежащего хэширующего алгоритма, основанного на Blowfish, и должен быть в диапазоне 04-31, значения вне данного диапазона вызовут отказ crypt(). -
CRYPT_SHA256
- хэш SHA-256 с шестнадцатисимвольной солью, начинающейся с $5$. Если строка с солью начинается с 'rounds=<N>$', число N будет использовано для обозначения количества раундов хэширования, по аналогии с весовым параметром в Blowfish. По умолчанию используемое количество раундов равно 5000, минимально доступно 1000 и максимально 999,999,999. Любой значение вне этого диапазона будет усечено до ближайшего лимита. -
CRYPT_SHA512
- хэш SHA-512 с шестнадцатисимвольной солью, начинающейся с $6$. Если строка с солью начинается с 'rounds=<N>$', число N будет использовано для обозначения количества раундов хэширования, по аналогии с весовым параметром в Blowfish. По умолчанию используемое количество раундов равно 5000, минимально доступно 1000 и максимально 999,999,999. Любой значение вне этого диапазона будет усечено до ближайшего лимита.
Замечание:
Начиная с версии PHP 5.3.0, PHP использует свою собственную реализацию, которая будет использована при отсутствии в системе какого-либо алгоритма.
Список параметров
-
str
-
Хэшируемая строка.
-
salt
-
Необязательный параметр с солью, на которой будет основано хэширование. Если не указан, поведение определяется по наличию реализованных алгоритмов в системе и может привести к неожиданным результатам.
Возвращаемые значения
Возвращает хэшированную строку или строку короче 13 символов, гарантированно отличающуюся от соли в случае ошибки.
Список изменений
Версия | Описание |
---|---|
5.3.2 | Добавлено хэширование алгоритмами SHA-256 и SHA-512, основанное на » реализации Ulrich Drepper. |
5.3.2 | Исправлено поведение Blowfish при некорректных раундах: теперь возвращается "ошибочная" строка ("*0" или "*1") вместо отката к использованию DES. |
5.3.0 | PHP теперь использует собственную реализацию MD5, стандартного DES, расширенного DES и Blowfish алгоритмов, которые будут использованы в случае отсутствия их поддержки в системе. |
Примеры
Пример #1 Пример использования crypt()
<?php
$password = crypt('mypassword'); // соль будет сгенерирована автоматически
/* Для проверки пароля в качестве параметра salt следует передавать результат работы
crypt() целиком во избежание проблем при использовании различных
алгоритмов (как уже было отмечено выше, стандартный DES-алгоритм
использует 2-символьную соль, а MD5 - 12-символьную. */
if (crypt($user_input, $password) == $password) {
echo "Пароль верен!";
}
?>
Пример #2 Использование crypt() и htpasswd
<?php
// пароль
$password = 'mypassword';
// получение хэша, соль генерируется автоматически
$hash = crypt($password);
?>
Пример #3 Использование crypt() с различными видами хэшей
<?php
if (CRYPT_STD_DES == 1) {
echo 'Стандартный DES: ' . crypt('rasmuslerdorf', 'rl') . "\n";
}
if (CRYPT_EXT_DES == 1) {
echo 'Расширенный DES: ' . crypt('rasmuslerdorf', '_J9..rasm') . "\n";
}
if (CRYPT_MD5 == 1) {
echo 'MD5: ' . crypt('rasmuslerdorf', '$1$rasmusle$') . "\n";
}
if (CRYPT_BLOWFISH == 1) {
echo 'Blowfish: ' . crypt('rasmuslerdorf', '$2a$07$usesomesillystringforsalt$') . "\n";
}
if (CRYPT_SHA256 == 1) {
echo 'SHA-256: ' . crypt('rasmuslerdorf', '$5$rounds=5000$usesomesillystringforsalt$') . "\n";
}
if (CRYPT_SHA512 == 1) {
echo 'SHA-512: ' . crypt('rasmuslerdorf', '$6$rounds=5000$usesomesillystringforsalt$') . "\n";
}
?>
Результатом выполнения данного примера будет что-то подобное:
Стандартный DES: rl.3StKT.4T8M Расширенный DES: _J9..rasmBYk8r9AiWNc MD5: $1$rasmusle$rISCgZzpwk3UhDidwXvin0 Blowfish: $2a$07$usesomesillystringfore2uDLvp1Ii2e./U9C8sBjqp8I90dH6hi SHA-256: $5$rounds=5000$usesomesillystri$KqJWpanXZHKq2BOB43TSaYhEWsQ1Lr5QNyPCDH/Tp.6 SHA-512: $6$rounds=5000$usesomesillystri$D4IrlXatmP7rx3P3InaxBeoomnAihCKRVQP22JZ6EY47Wc6BkroIuUUBOov1i.S5KPgErtP/EN5mcO.ChWQW21
Примечания
Замечание: Функция расшифровки отсутствует, так как crypt() использует необратимый алгоритм хэширования.
- addcslashes
- addslashes
- bin2hex
- chop
- chr
- chunk_split
- convert_cyr_string
- convert_uudecode
- convert_uuencode
- count_chars
- crc32
- crypt
- echo
- explode
- fprintf
- get_html_translation_table
- hebrev
- hebrevc
- hex2bin
- html_entity_decode
- htmlentities
- htmlspecialchars_decode
- htmlspecialchars
- implode
- join
- lcfirst
- levenshtein
- localeconv
- ltrim
- md5_file
- md5
- metaphone
- money_format
- nl_langinfo
- nl2br
- number_format
- ord
- parse_str
- printf
- quoted_printable_decode
- quoted_printable_encode
- quotemeta
- rtrim
- setlocale
- sha1_file
- sha1
- similar_text
- soundex
- sprintf
- sscanf
- str_getcsv
- str_ireplace
- str_pad
- str_repeat
- str_replace
- str_rot13
- str_shuffle
- str_split
- str_word_count
- strcasecmp
- strchr
- strcmp
- strcoll
- strcspn
- strip_tags
- stripcslashes
- stripos
- stripslashes
- stristr
- strlen
- strnatcasecmp
- strnatcmp
- strncasecmp
- strncmp
- strpbrk
- strpos
- strrchr
- strrev
- strripos
- strrpos
- strspn
- strstr
- strtok
- strtolower
- strtoupper
- strtr
- substr_compare
- substr_count
- substr_replace
- substr
- trim
- ucfirst
- ucwords
- vfprintf
- vprintf
- vsprintf
- wordwrap
Коментарии
Here is an expression to generate pseudorandom salt for the CRYPT_BLOWFISH hash type:
<?php $salt = substr(str_replace('+', '.', base64_encode(pack('N4', mt_rand(), mt_rand(), mt_rand(), mt_rand()))), 0, 22); ?>
It is intended for use on systems where mt_getrandmax() == 2147483647.
The salt created will be 128 bits in length, padded to 132 bits and then expressed in 22 base64 characters. (CRYPT_BLOWFISH only uses 128 bits for the salt, even though there are 132 bits in 22 base64 characters. If you examine the CRYPT_BLOWFISH input and output, you can see that it ignores the last four bits on input, and sets them to zero on output.)
Note that the high-order bits of the four 32-bit dwords returned by mt_rand() will always be zero (since mt_getrandmax == 2^31), so only 124 of the 128 bits will be pseudorandom. I found that acceptable for my application.
To generate salt use mcrypt_create_iv() not mt_rand() because no matter how many times you call mt_rand() it will only have at most 32 bits of entropy. Which you will start seeing salt collisions after about 2^16 users. mt_rand() is seeded poorly so it should happen sooner.
For bcrypt this will actually generate a 128 bit salt:
<?php $salt = strtr(base64_encode(mcrypt_create_iv(16, MCRYPT_DEV_URANDOM)), '+', '.'); ?>
*** Bike shed ***
The last character in the 22 character salt is 2 bits.
base64_encode() will have these four character "AQgw"
bcrypt will have these four character ".Oeu"
You don't need to do a full translate because they "round" to different characters:
echo crypt('', '$2y$05$.....................A') . "\n";
echo crypt('', '$2y$05$.....................Q') . "\n";
echo crypt('', '$2y$05$.....................g') . "\n";
echo crypt('', '$2y$05$.....................w') . "\n";
$2y$05$......................J2ihDv8vVf7QZ9BsaRrKyqs2tkn55Yq
$2y$05$.....................O/jw2XygQa2.LrIT7CFCBQowLowDP6Y.
$2y$05$.....................eDOx4wMcy7WU.kE21W6nJfdMimsBE3V6
$2y$05$.....................uMMcgjnOELIa6oydRivPkiMrBG8.aFp.
The crypt() function cant handle plus signs correctly. So if for example you are using crypt in a login function, use urlencode on the password first to make sure that the login procedure can handle any character:
<?php
$user_input = '12+#æ345';
$pass = urlencode($user_input));
$pass_crypt = crypt($pass);
if ($pass_crypt == crypt($pass, $pass_crypt)) {
echo "Success! Valid password";
} else {
echo "Invalid password";
}
?>
As I understand it, blowfish is generally seen a secure hashing algorithm, even for enterprise use (correct me if I'm wrong). Because of this, I created functions to create and check secure password hashes using this algorithm, and using the (also deemed cryptographically secure) openssl_random_pseudo_bytes function to generate the salt.
<?php
/*
* Generate a secure hash for a given password. The cost is passed
* to the blowfish algorithm. Check the PHP manual page for crypt to
* find more information about this setting.
*/
function generate_hash($password, $cost=11){
/* To generate the salt, first generate enough random bytes. Because
* base64 returns one character for each 6 bits, the we should generate
* at least 22*6/8=16.5 bytes, so we generate 17. Then we get the first
* 22 base64 characters
*/
$salt=substr(base64_encode(openssl_random_pseudo_bytes(17)),0,22);
/* As blowfish takes a salt with the alphabet ./A-Za-z0-9 we have to
* replace any '+' in the base64 string with '.'. We don't have to do
* anything about the '=', as this only occurs when the b64 string is
* padded, which is always after the first 22 characters.
*/
$salt=str_replace("+",".",$salt);
/* Next, create a string that will be passed to crypt, containing all
* of the settings, separated by dollar signs
*/
$param='$'.implode('$',array(
"2y", //select the most secure version of blowfish (>=PHP 5.3.7)
str_pad($cost,2,"0",STR_PAD_LEFT), //add the cost in two digits
$salt //add the salt
));
//now do the actual hashing
return crypt($password,$param);
}
/*
* Check the password against a hash generated by the generate_hash
* function.
*/
function validate_pw($password, $hash){
/* Regenerating the with an available hash as the options parameter should
* produce the same hash if the same password is passed.
*/
return crypt($password, $hash)==$hash;
}
?>
The #2 comment on this comments page (as of Feb 2015) is 9 years old and recommends phpass. I have independently security audited this product and, while it continues to be recommended for password security, it is actually insecure and should NOT be used. It hasn't seen any updates in years (still at v0.3) and there are more recent alternatives such as using the newer built-in PHP password_hash() function that are much better. Everyone, please take a few moments to confirm what I'm saying is accurate (i.e. review the phpass code for yourself) and then click the down arrow to sink the phpass comment to the bottom. You'll be increasing security across the Internet by doing so.
For those who want details: md5() with microtime() are a fallback position within the source code of phpass. Instead of terminating, it continues to execute code. The author's intentions of trying to work everywhere are admirable but, when it comes to application security, that stance actually backfires. The only correct answer in a security context is to terminate the application rather than fallback to a weak position that can potentially be exploited (usually by forcing that weaker position to happen).
The crypt_gensalt function (from the xpass extension) makes usage of this function much easier, ex:
<?php
$salt = crypt_gensalt(CRYPT_PREFIX_BLOWFISH, 10);
$hash = crypt($secret, $salt);