diff options
-rw-r--r-- | package.xml | 15 | ||||
-rw-r--r-- | php_xpass.h | 2 | ||||
-rw-r--r-- | tests/crypt_checksalt.phpt | 12 | ||||
-rw-r--r-- | tests/crypt_gensalt.phpt | 25 | ||||
-rw-r--r-- | tests/crypt_preferred_method.phpt | 9 | ||||
-rw-r--r-- | tests/password_compat.phpt | 22 | ||||
-rw-r--r-- | xpass.c | 56 | ||||
-rw-r--r-- | xpass.stub.php | 58 | ||||
-rw-r--r-- | xpass_arginfo.h | 45 |
9 files changed, 239 insertions, 5 deletions
diff --git a/package.xml b/package.xml index 4b0cafa..b47f016 100644 --- a/package.xml +++ b/package.xml @@ -18,8 +18,8 @@ distributions, using extended crypt library (libxcrypt): </lead> <date>2024-09-09</date> <version> - <release>1.0.1dev</release> - <api>1.0.0</api> + <release>1.1.0dev</release> + <api>1.1.0</api> </version> <stability> <release>stable</release> @@ -27,7 +27,9 @@ distributions, using extended crypt library (libxcrypt): </stability> <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license> <notes> -- +- add crypt_gensalt(?string $salt = null, int $count = 0): ?string {} +- add crypt_preferred_method(): ?string {} +- add crypt_checksalt(string $salt): int {} </notes> <contents> <dir name="/"> @@ -35,11 +37,18 @@ distributions, using extended crypt library (libxcrypt): <file name="config.m4" role="src"/> <file name="php_xpass.h" role="src" /> <file name="xpass.c" role="src"/> + <file name="xpass.stub.php" role="src"/> + <file name="xpass_arginfo.h" role="src"/> <!-- documentation --> <file name="CREDITS" role="doc"/> <file name="LICENSE" role="doc"/> <file name="README.md" role="doc"/> + <!-- tests --> <dir name ="tests"> + <file name="crypt_checksalt.phpt" role="test"/> + <file name="crypt_gensalt.phpt" role="test"/> + <file name="crypt_preferred_method.phpt" role="test"/> + <file name="password_compat.phpt" role="test"/> <file name="sha512.phpt" role="test"/> <file name="xpass.phpt" role="test"/> <file name="yescrypt.phpt" role="test"/> diff --git a/php_xpass.h b/php_xpass.h index 05fbf79..6b1f0f2 100644 --- a/php_xpass.h +++ b/php_xpass.h @@ -22,7 +22,7 @@ extern zend_module_entry xpass_module_entry; #define phpext_xpass_ptr &xpass_module_entry -#define PHP_XPASS_VERSION "1.0.1-dev" +#define PHP_XPASS_VERSION "1.1.0-dev" #define PHP_XPASS_AUTHOR "Remi Collet" #define PHP_XPASS_LICENSE "PHP-3.01" diff --git a/tests/crypt_checksalt.phpt b/tests/crypt_checksalt.phpt new file mode 100644 index 0000000..4fbd8bf --- /dev/null +++ b/tests/crypt_checksalt.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test crypt_checksalt +--FILE-- +<?php +var_dump(crypt_checksalt(crypt_gensalt(XPASS_CRYPT_STD_DES)) === CRYPT_SALT_METHOD_LEGACY); +var_dump(crypt_checksalt(crypt_gensalt()) === CRYPT_SALT_OK); +var_dump(crypt_checksalt("!not_a_valid_hash") === CRYPT_SALT_INVALID); +?> +--EXPECT-- +bool(true) +bool(true) +bool(true) diff --git a/tests/crypt_gensalt.phpt b/tests/crypt_gensalt.phpt new file mode 100644 index 0000000..b838a04 --- /dev/null +++ b/tests/crypt_gensalt.phpt @@ -0,0 +1,25 @@ +--TEST-- +Test crypt_gensalt +--FILE-- +<?php +var_dump(crypt_gensalt(XPASS_CRYPT_STD_DES)); +var_dump(crypt_gensalt(XPASS_CRYPT_EXT_DES)); +var_dump(crypt_gensalt(XPASS_CRYPT_MD5)); +var_dump(crypt_gensalt(XPASS_CRYPT_BLOWFISH)); +var_dump(crypt_gensalt(XPASS_CRYPT_SHA256)); +var_dump(crypt_gensalt(XPASS_CRYPT_SHA512)); +var_dump(crypt_gensalt(XPASS_CRYPT_SCRYPT)); +var_dump(crypt_gensalt(XPASS_CRYPT_GOST_YESCRYPT)); +var_dump(crypt_gensalt(XPASS_CRYPT_YESCRYPT)); + +?> +--EXPECTF-- +string(2) "%s" +string(9) "_%s" +string(11) "$1$%s" +string(29) "$2y$%s" +string(19) "$5$%s" +string(19) "$6$%s" +string(36) "$7$%s" +string(30) "$gy$%s" +string(29) "$y$j%s" diff --git a/tests/crypt_preferred_method.phpt b/tests/crypt_preferred_method.phpt new file mode 100644 index 0000000..f222639 --- /dev/null +++ b/tests/crypt_preferred_method.phpt @@ -0,0 +1,9 @@ +--TEST-- +Test crypt_preferred_method +--FILE-- +<?php +var_dump(crypt_preferred_method()); +?> +--EXPECTF-- +string(%d) "$%s$" + diff --git a/tests/password_compat.phpt b/tests/password_compat.phpt new file mode 100644 index 0000000..3dd6ad2 --- /dev/null +++ b/tests/password_compat.phpt @@ -0,0 +1,22 @@ +--TEST-- +Test crypt compatibility with password_hash +--FILE-- +<?php +$secret = 'mysecret'; + +/* generate with password_hash, check with both */ +$h = password_hash($secret, PASSWORD_BCRYPT); +var_dump($h, password_verify($secret, $h), $h===crypt($secret, $h)); + +/* generate with crypt, check with both */ +$h = crypt($secret, crypt_gensalt(XPASS_CRYPT_BLOWFISH)); +var_dump($h, password_verify($secret, $h), $h===crypt($secret, $h)); +?> +--EXPECTF-- +string(60) "$2y$%s$%s" +bool(true) +bool(true) +string(60) "$2y$%s$%s" +bool(true) +bool(true) + @@ -26,6 +26,8 @@ #include "php_xpass.h" #include <crypt.h> +#include "xpass_arginfo.h" + /* {{{ PHP_RINIT_FUNCTION */ PHP_RINIT_FUNCTION(xpass) { @@ -149,8 +151,60 @@ static const php_password_algo xpass_algo_yescrypt = { NULL, }; +/* {{{ 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)); +} +/* }}} */ + PHP_MINIT_FUNCTION(xpass) /* {{{ */ { + register_xpass_symbols(module_number); + #ifdef HAVE_CRYPT_SHA512 if (FAILURE == php_password_algo_register("6", &xpass_algo_sha512)) { return FAILURE; @@ -172,7 +226,7 @@ PHP_MINIT_FUNCTION(xpass) /* {{{ */ { zend_module_entry xpass_module_entry = { STANDARD_MODULE_HEADER, "xpass", /* Extension name */ - NULL, /* zend_function_entry */ + ext_functions, /* zend_function_entry */ PHP_MINIT(xpass), /* PHP_MINIT - Module initialization */ NULL, /* PHP_MSHUTDOWN - Module shutdown */ PHP_RINIT(xpass), /* PHP_RINIT - Request initialization */ diff --git a/xpass.stub.php b/xpass.stub.php new file mode 100644 index 0000000..4038b41 --- /dev/null +++ b/xpass.stub.php @@ -0,0 +1,58 @@ +<?php + +/** @generate-class-entries */ + +/* use XPASS prefix to avoid conflicts with standard constants */ + +/** @var string */ +const XPASS_CRYPT_STD_DES = ''; +/** @var string */ +const XPASS_CRYPT_EXT_DES = '_'; +/** @var string */ +const XPASS_CRYPT_MD5 = '$1$'; +/** @var string */ +const XPASS_CRYPT_BLOWFISH = '$2y$'; +/** @var string */ +const XPASS_CRYPT_SHA256 = '$5$'; +/** @var string */ +const XPASS_CRYPT_SHA512 = '$6$'; +/** @var string */ +const XPASS_CRYPT_SCRYPT = '$7$'; +/** @var string */ +const XPASS_CRYPT_GOST_YESCRYPT = '$gy$'; +/** @var string */ +const XPASS_CRYPT_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; + + +function crypt_gensalt(?string $salt = null, int $count = 0): ?string {} + +function crypt_preferred_method(): ?string {} + +function crypt_checksalt(string $salt): int {} + diff --git a/xpass_arginfo.h b/xpass_arginfo.h new file mode 100644 index 0000000..dcd9a50 --- /dev/null +++ b/xpass_arginfo.h @@ -0,0 +1,45 @@ +/* This is a generated file, edit the .stub.php file instead. + * Stub hash: 6a2b53f488db292839749c125a6d81f89316e9c9 */ + +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() + + +ZEND_FUNCTION(crypt_gensalt); +ZEND_FUNCTION(crypt_preferred_method); +ZEND_FUNCTION(crypt_checksalt); + + +static const zend_function_entry ext_functions[] = { + ZEND_FE(crypt_gensalt, arginfo_crypt_gensalt) + ZEND_FE(crypt_preferred_method, arginfo_crypt_preferred_method) + ZEND_FE(crypt_checksalt, arginfo_crypt_checksalt) + ZEND_FE_END +}; + +static void register_xpass_symbols(int module_number) +{ + REGISTER_STRING_CONSTANT("XPASS_CRYPT_STD_DES", "", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("XPASS_CRYPT_EXT_DES", "_", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("XPASS_CRYPT_MD5", "$1$", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("XPASS_CRYPT_BLOWFISH", "$2y$", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("XPASS_CRYPT_SHA256", "$5$", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("XPASS_CRYPT_SHA512", "$6$", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("XPASS_CRYPT_SCRYPT", "$7$", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("XPASS_CRYPT_GOST_YESCRYPT", "$gy$", CONST_PERSISTENT); + REGISTER_STRING_CONSTANT("XPASS_CRYPT_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); +} |