diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 68cc86e7b1fa5..b5ad87eb619eb 100644 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -395,6 +395,49 @@ const CRYPT_SHA256 = 1; /** @var int */ const CRYPT_SHA512 = 1; +/** @var string */ +const CRYPT_PREFIX_STD_DES = ''; +/** @var string */ +const CRYPT_PREFIX_EXT_DES = '_'; +/** @var string */ +const CRYPT_PREFIX_MD5 = '$1$'; +/** @var string */ +const CRYPT_PREFIX_BLOWFISH = '$2y$'; +/** @var string */ +const CRYPT_PREFIX_SHA256 = '$5$'; +/** @var string */ +const CRYPT_PREFIX_SHA512 = '$6$'; +/** @var string */ +const CRYPT_PREFIX_SCRYPT = '$7$'; +/** @var string */ +const CRYPT_PREFIX_GOST_YESCRYPT = '$gy$'; +/** @var string */ +const CRYPT_PREFIX_YESCRYPT = '$y$'; +/** + * @var int + * @cvalue CRYPT_SALT_OK + */ +const CRYPT_SALT_OK = UNKNOWN; +/** + * @var int + * @cvalue CRYPT_SALT_INVALID + */ +const CRYPT_SALT_INVALID = UNKNOWN; +/** + * @var int + * @cvalue CRYPT_SALT_METHOD_DISABLED + */ +const CRYPT_SALT_METHOD_DISABLED = UNKNOWN; +/** + * @var int + * @cvalue CRYPT_SALT_METHOD_LEGACY + */ +const CRYPT_SALT_METHOD_LEGACY = UNKNOWN; +/** + * @var int + * @cvalue CRYPT_SALT_TOO_CHEAP + */ +const CRYPT_SALT_TOO_CHEAP = UNKNOWN; /* dns.c */ @@ -2111,6 +2154,12 @@ function crc32(string $string): int {} /** @refcount 1 */ function crypt(#[\SensitiveParameter] string $string, string $salt): string {} +function crypt_gensalt(?string $salt = null, int $count = 0): ?string {} + +function crypt_preferred_method(): ?string {} + +function crypt_checksalt(string $salt): int {} + /* datetime.c */ #ifdef HAVE_STRPTIME diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index e429281125053..a8bb01a3a2166 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 504f4172ac1d64535719234888400063eb37361b */ + * Stub hash: cf1c200d03b18a95bfd616f26c3b41c1b438174a */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -615,6 +615,18 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_crypt, 0, 2, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, salt, IS_STRING, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_crypt_gensalt, 0, 0, IS_STRING, 1) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, salt, IS_STRING, 1, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, count, IS_LONG, 0, "0") +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_crypt_preferred_method, 0, 0, IS_STRING, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_crypt_checksalt, 0, 1, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, salt, IS_STRING, 0) +ZEND_END_ARG_INFO() + #if defined(HAVE_STRPTIME) ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_strptime, 0, 2, MAY_BE_ARRAY|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, timestamp, IS_STRING, 0) @@ -2454,6 +2466,9 @@ ZEND_FUNCTION(sys_getloadavg); ZEND_FUNCTION(get_browser); ZEND_FUNCTION(crc32); ZEND_FUNCTION(crypt); +ZEND_FUNCTION(crypt_gensalt); +ZEND_FUNCTION(crypt_preferred_method); +ZEND_FUNCTION(crypt_checksalt); #if defined(HAVE_STRPTIME) ZEND_FUNCTION(strptime); #endif @@ -3050,6 +3065,9 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(get_browser, arginfo_get_browser) ZEND_RAW_FENTRY("crc32", zif_crc32, arginfo_crc32, ZEND_ACC_COMPILE_TIME_EVAL, NULL, NULL) ZEND_FE(crypt, arginfo_crypt) + ZEND_FE(crypt_gensalt, arginfo_crypt_gensalt) + ZEND_FE(crypt_preferred_method, arginfo_crypt_preferred_method) + ZEND_FE(crypt_checksalt, arginfo_crypt_checksalt) #if defined(HAVE_STRPTIME) ZEND_RAW_FENTRY("strptime", zif_strptime, arginfo_strptime, ZEND_ACC_DEPRECATED, NULL, NULL) #endif @@ -3583,6 +3601,20 @@ static void register_basic_functions_symbols(int module_number) REGISTER_LONG_CONSTANT("CRYPT_BLOWFISH", 1, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_SHA256", 1, CONST_PERSISTENT); REGISTER_LONG_CONSTANT("CRYPT_SHA512", 1, CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("CRYPT_PREFIX_STD_DES", "", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("CRYPT_PREFIX_EXT_DES", "_", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("CRYPT_PREFIX_MD5", "$1$", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("CRYPT_PREFIX_BLOWFISH", "$2y$", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("CRYPT_PREFIX_SHA256", "$5$", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("CRYPT_PREFIX_SHA512", "$6$", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("CRYPT_PREFIX_SCRYPT", "$7$", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("CRYPT_PREFIX_GOST_YESCRYPT", "$gy$", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("CRYPT_PREFIX_YESCRYPT", "$y$", CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("CRYPT_SALT_OK", CRYPT_SALT_OK, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("CRYPT_SALT_INVALID", CRYPT_SALT_INVALID, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("CRYPT_SALT_METHOD_DISABLED", CRYPT_SALT_METHOD_DISABLED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("CRYPT_SALT_METHOD_LEGACY", CRYPT_SALT_METHOD_LEGACY, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("CRYPT_SALT_TOO_CHEAP", CRYPT_SALT_TOO_CHEAP, CONST_PERSISTENT); #if (defined(PHP_WIN32) || (defined(HAVE_DNS_SEARCH_FUNC) && defined(HAVE_FULL_DNS_FUNCS))) REGISTER_LONG_CONSTANT("DNS_A", PHP_DNS_A, CONST_PERSISTENT); #endif diff --git a/ext/standard/crypt.c b/ext/standard/crypt.c index 14eb6cda9735a..ea36c071e6a51 100644 --- a/ext/standard/crypt.c +++ b/ext/standard/crypt.c @@ -218,3 +218,53 @@ PHP_FUNCTION(crypt) RETURN_STR(result); } /* }}} */ + +/* {{{ Generates a salt for algo */ +PHP_FUNCTION(crypt_gensalt) +{ + char salt[CRYPT_GENSALT_OUTPUT_SIZE + 1]; + char *prefix = NULL; + size_t prefix_len = 0; + zend_long count = 0; + + ZEND_PARSE_PARAMETERS_START(0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_STRING(prefix, prefix_len) + Z_PARAM_LONG(count) + ZEND_PARSE_PARAMETERS_END(); + + if (crypt_gensalt_rn(prefix, (unsigned long)count, NULL, 0, salt, CRYPT_GENSALT_OUTPUT_SIZE)) { + RETURN_STRING(salt); + } + RETURN_NULL(); +} +/* }}} */ + +/* {{{ Get preferred hasing method prefix */ +PHP_FUNCTION(crypt_preferred_method) +{ + const char *prefix; + + ZEND_PARSE_PARAMETERS_NONE(); + + prefix = crypt_preferred_method(); + if (prefix) { + RETURN_STRING(prefix); + } + RETURN_NULL(); +} +/* }}} */ + +/* {{{ Determine whether the user's passphrase should be re-hashed using the currently preferred hashing method */ +PHP_FUNCTION(crypt_checksalt) +{ + char *prefix; + size_t prefix_len; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STRING(prefix, prefix_len) + ZEND_PARSE_PARAMETERS_END(); + + RETURN_LONG(crypt_checksalt(prefix)); +} +/* }}} */ diff --git a/ext/standard/php_crypt.h b/ext/standard/php_crypt.h index b7111dfd21b1a..5965e63e4bf6c 100644 --- a/ext/standard/php_crypt.h +++ b/ext/standard/php_crypt.h @@ -19,12 +19,24 @@ #ifndef PHP_CRYPT_H #define PHP_CRYPT_H +#ifdef HAVE_CRYPT_H +# if defined(CRYPT_R_GNU_SOURCE) && !defined(_GNU_SOURCE) +# define _GNU_SOURCE +# endif +# include +#endif + PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const char *salt, int salt_len, bool quiet); PHP_MINIT_FUNCTION(crypt); PHP_MSHUTDOWN_FUNCTION(crypt); PHP_RINIT_FUNCTION(crypt); +#ifdef CRYPT_GENSALT_OUTPUT_SIZE +/* use salt length from library (192) */ +#define PHP_MAX_SALT_LEN CRYPT_GENSALT_OUTPUT_SIZE +#else /* sha512 crypt has the maximal salt length of 123 characters */ #define PHP_MAX_SALT_LEN 123 +#endif #endif diff --git a/ext/standard/tests/crypt/password_compat.phpt b/ext/standard/tests/crypt/password_compat.phpt new file mode 100644 index 0000000000000..2571b02e9ab77 --- /dev/null +++ b/ext/standard/tests/crypt/password_compat.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test crypt compatibility with password_hash +--FILE-- + +--EXPECTF-- +string(60) "$2y$%s$%s" +bool(true) +bool(true) +string(60) "$2y$%s$%s" +bool(true) +bool(true) +