diff options
| author | Remi Collet <remi@remirepo.net> | 2026-01-13 11:24:11 +0100 |
|---|---|---|
| committer | Remi Collet <remi@php.net> | 2026-01-13 11:24:11 +0100 |
| commit | e8edf1395b25ee0dba11a00b666c06280aef440c (patch) | |
| tree | 3f3bde322cddfd3bccf5be2217a0473618586ec9 | |
| parent | a7d635afb702594870559d54453ea7b5dcaa760a (diff) | |
| -rw-r--r-- | CHANGELOG.md | 6 | ||||
| -rw-r--r-- | README.md | 4 | ||||
| -rw-r--r-- | config.m4 | 18 | ||||
| -rw-r--r-- | package.xml | 13 | ||||
| -rw-r--r-- | php_xpass.h | 2 | ||||
| -rw-r--r-- | tests/crypt_gensalt2.phpt | 15 | ||||
| -rw-r--r-- | tests/sm3crypt.phpt | 71 | ||||
| -rw-r--r-- | tests/sm3yescrypt.phpt | 71 | ||||
| -rw-r--r-- | xpass.c | 63 | ||||
| -rw-r--r-- | xpass.stub.php | 6 | ||||
| -rw-r--r-- | xpass_arginfo.h | 8 |
11 files changed, 265 insertions, 12 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index e5ecd6c..a8d0ef8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Unreleased -- +# Version 1.2.0 - 2026-01-13 + +- add SM3 hash algos available in libxcrypt 4.5 +- add CRYPT_PREFIX_SM3CRYPT and CRYPT_PREFIX_SM3_YESCRYPT constants +- add PASSWORD_SM3CRYPT and PASSWORD_SM3_YESCRYPT constants # Version 1.1.0 - 2024-09-26 @@ -7,6 +7,8 @@ This extension provides password hashing algorithms used by Linux distributions. * **sha512** (`$6$`) provided for legacy as used on some old distributions (ex: RHEL-8) * **yescrypt** (`$y$`) used on modern distributions +* **sm3crypt** (`$sm3$`) +* **sm3yescrypt** (`$sm3y$`) Notices: these can be fast, don't expect improved security level. @@ -28,6 +30,8 @@ See the Linux man pages or [PHP Documentation](https://www.php.net/xpass) * yescrypt: 0.14" with cost=6 * yescrypt: 0.30" with cost=7 * yescrypt: 0.62" with cost=8 +* sm3crypt: 0.01" +* yessm3crypt: 0.02" # Sources @@ -50,6 +50,24 @@ int main(void) { AC_MSG_RESULT([missing]) ]) + AC_MSG_CHECKING([for sm3 algo]) + AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include <string.h> +#include <unistd.h> +#include <crypt.h> +#include <stdlib.h> + +int main(void) { + char salt[8]; + salt[0]='$'; salt[1]='s'; salt[2]='m'; salt[3]='3'; salt[4]='$'; salt[5]=0; + return crypt_gensalt(salt, 0, NULL, 0) ? 0 : 1; +}]])],[ + AC_DEFINE([HAVE_CRYPT_SM3], [1], [ Have sm3 hash support ]) + AC_MSG_RESULT([available]) + ], [ + AC_MSG_RESULT([missing]) + ]) + CFLAGS=$old_CFLAGS LIBS=$old_LIBS diff --git a/package.xml b/package.xml index 7fb2348..0db5bc5 100644 --- a/package.xml +++ b/package.xml @@ -9,6 +9,8 @@ distributions, using extended crypt library (libxcrypt): * sha512 provided for legacy as used on some old distributions * yescrypt used on modern distributions +* sm3crypt +* sm3yescrypt It also provides additional functions from libxcrypt missing in core PHP: @@ -24,9 +26,9 @@ See PHP documentation on https://www.php.net/xpass <email>remi@php.net</email> <active>yes</active> </lead> - <date>2024-09-26</date> + <date>2026-01-13</date> <version> - <release>1.1.1dev</release> + <release>1.2.0</release> <api>1.1.0</api> </version> <stability> @@ -35,7 +37,9 @@ See PHP documentation on https://www.php.net/xpass </stability> <license uri="https://www.php.net/license/3_01.txt" filesource="LICENSE">PHP-3.01</license> <notes><![CDATA[ -- +- add SM3 hash algos available in libxcrypt 4.5 +- add CRYPT_PREFIX_SM3CRYPT and CRYPT_PREFIX_SM3_YESCRYPT constants +- add PASSWORD_SM3CRYPT and PASSWORD_SM3_YESCRYPT constants ]]></notes> <contents> <dir name="/"> @@ -54,9 +58,12 @@ See PHP documentation on https://www.php.net/xpass <dir name ="tests"> <file name="crypt_checksalt.phpt" role="test"/> <file name="crypt_gensalt.phpt" role="test"/> + <file name="crypt_gensalt2.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="sm3crypt.phpt" role="test"/> + <file name="sm3yescrypt.phpt" role="test"/> <file name="xpass.phpt" role="test"/> <file name="yescrypt.phpt" role="test"/> </dir> diff --git a/php_xpass.h b/php_xpass.h index 0d10ff2..d904a0a 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.1.0" +#define PHP_XPASS_VERSION "1.2.0" #define PHP_XPASS_AUTHOR "Remi Collet" #define PHP_XPASS_LICENSE "PHP-3.01" diff --git a/tests/crypt_gensalt2.phpt b/tests/crypt_gensalt2.phpt new file mode 100644 index 0000000..864c614 --- /dev/null +++ b/tests/crypt_gensalt2.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test crypt_gensalt +--SKIPIF-- +<?php +if (!defined("CRYPT_PREFIX_SM3CRYPT")) die("skip SM3CRYPT missing"); +?> +--FILE-- +<?php +var_dump(crypt_gensalt(CRYPT_PREFIX_SM3CRYPT)); +var_dump(crypt_gensalt(CRYPT_PREFIX_SM3_YESCRYPT)); + +?> +--EXPECTF-- +string(21) "$sm3$%s" +string(32) "$sm3y$%s" diff --git a/tests/sm3crypt.phpt b/tests/sm3crypt.phpt new file mode 100644 index 0000000..c398eed --- /dev/null +++ b/tests/sm3crypt.phpt @@ -0,0 +1,71 @@ +--TEST-- +Check sm3crypt algo +--EXTENSIONS-- +xpass +--SKIPIF-- +<?php +if (!defined("PASSWORD_SM3CRYPT")) die("skip SM3CRYPT missing"); +?> +--FILE-- +<?php +$data = [ + 'mysecret' => '$sm3$wjwOAHL3D6DzuOsN$QF8mPXc8WfTfOE1PsWw05FgUogEEWqE5jh/ZlhCFof.', + 'remicollet' => '$sm3$L/iCXvrL76KHTQBh$Jj0jcZoeFgH7wb3Tepl6yiVhL4Pm5Kd6GcInazUcOs.', +]; +foreach($data as $pass => $hash) { + echo "-- $pass\n"; + var_dump(password_verify($pass, $hash)); + var_dump(password_get_info($hash)); + var_dump(password_verify($pass."bad", $hash)); + var_dump(password_verify($pass, $hash."bad")); + var_dump(password_needs_rehash($hash, PASSWORD_SM3CRYPT)); +} + +echo "-- no cost\n"; +$pass = 'secret'; +var_dump($hash = password_hash($pass, PASSWORD_SM3CRYPT)); +var_dump(password_get_info($hash)); +var_dump(password_verify($pass, $hash)); +?> +--EXPECTF-- +-- mysecret +bool(true) +array(3) { + ["algo"]=> + string(3) "sm3" + ["algoName"]=> + string(8) "sm3crypt" + ["options"]=> + array(0) { + } +} +bool(false) +bool(false) +bool(true) +-- remicollet +bool(true) +array(3) { + ["algo"]=> + string(3) "sm3" + ["algoName"]=> + string(8) "sm3crypt" + ["options"]=> + array(0) { + } +} +bool(false) +bool(false) +bool(true) +-- no cost +string(65) "$sm3$%s" +array(3) { + ["algo"]=> + string(3) "sm3" + ["algoName"]=> + string(8) "sm3crypt" + ["options"]=> + array(0) { + } +} +bool(true) + diff --git a/tests/sm3yescrypt.phpt b/tests/sm3yescrypt.phpt new file mode 100644 index 0000000..a0884d9 --- /dev/null +++ b/tests/sm3yescrypt.phpt @@ -0,0 +1,71 @@ +--TEST-- +Check sm3yescrypt algo +--EXTENSIONS-- +xpass +--SKIPIF-- +<?php +if (!defined("PASSWORD_SM3_YESCRYPT")) die("skip SM3_YESCRYPT missing"); +?> +--FILE-- +<?php +$data = [ + 'mysecret' => '$sm3y$j9T$FeOt/DFtz1Mm8/mtgIer2.$MtA20j5f5L.Jz8MM4KuKCFgPstmpnswmC2/9BEPwND.', + 'remicollet' => '$sm3y$j9T$ElHlNepC6e7htB1BgBbe4.$VXOJS4j0v49cNKDN/6i66F4nwvTCUT5GsPwqKEewSI/', +]; +foreach($data as $pass => $hash) { + echo "-- $pass\n"; + var_dump(password_verify($pass, $hash)); + var_dump(password_get_info($hash)); + var_dump(password_verify($pass."bad", $hash)); + var_dump(password_verify($pass, $hash."bad")); + var_dump(password_needs_rehash($hash, PASSWORD_SM3_YESCRYPT)); +} + +echo "-- no cost\n"; +$pass = 'secret'; +var_dump($hash = password_hash($pass, PASSWORD_SM3_YESCRYPT)); +var_dump(password_get_info($hash)); +var_dump(password_verify($pass, $hash)); +?> +--EXPECTF-- +-- mysecret +bool(true) +array(3) { + ["algo"]=> + string(4) "sm3y" + ["algoName"]=> + string(11) "sm3yescrypt" + ["options"]=> + array(0) { + } +} +bool(false) +bool(false) +bool(false) +-- remicollet +bool(true) +array(3) { + ["algo"]=> + string(4) "sm3y" + ["algoName"]=> + string(11) "sm3yescrypt" + ["options"]=> + array(0) { + } +} +bool(false) +bool(false) +bool(false) +-- no cost +string(76) "$sm3y$%s" +array(3) { + ["algo"]=> + string(4) "sm3y" + ["algoName"]=> + string(11) "sm3yescrypt" + ["options"]=> + array(0) { + } +} +bool(true) + @@ -58,6 +58,11 @@ PHP_MINFO_FUNCTION(xpass) #else php_info_print_table_row(2, "yescrypt hash", "no"); #endif +#ifdef HAVE_CRYPT_SM3 + php_info_print_table_row(2, "sm3 hash", "yes"); +#else + php_info_print_table_row(2, "sm3 hash", "no"); +#endif php_info_print_table_end(); } /* }}} */ @@ -97,13 +102,27 @@ static zend_string *php_xpass_hash(const zend_string *password, zend_array *opti return zend_string_init(data.output, strlen(data.output), 0); } +#ifdef HAVE_CRYPT_YESCRYPT static zend_string *php_xpass_yescrypt_hash(const zend_string *password, zend_array *options) { return php_xpass_hash(password, options, "$y$"); } +#endif +#ifdef HAVE_CRYPT_SHA512 static zend_string *php_xpass_sha512_hash(const zend_string *password, zend_array *options) { return php_xpass_hash(password, options, "$6$"); } +#endif + +#ifdef HAVE_CRYPT_SM3 +static zend_string *php_xpass_sm3crypt_hash(const zend_string *password, zend_array *options) { + return php_xpass_hash(password, options, "$sm3$"); +} + +static zend_string *php_xpass_sm3yescrypt_hash(const zend_string *password, zend_array *options) { + return php_xpass_hash(password, options, "$sm3y$"); +} +#endif static bool php_xpass_verify(const zend_string *password, const zend_string *hash) { struct crypt_data data; @@ -130,6 +149,7 @@ static bool php_xpass_needs_rehash(const zend_string *hash, zend_array *options) return 0; } +#ifdef HAVE_CRYPT_SHA512 static const php_password_algo xpass_algo_sha512 = { "sha512", php_xpass_sha512_hash, @@ -138,7 +158,9 @@ static const php_password_algo xpass_algo_sha512 = { NULL, // php_xpass_yescrypt_get_info, NULL, }; +#endif +#ifdef HAVE_CRYPT_YESCRYPT static const php_password_algo xpass_algo_yescrypt = { "yescrypt", php_xpass_yescrypt_hash, @@ -147,6 +169,27 @@ static const php_password_algo xpass_algo_yescrypt = { NULL, // php_xpass_yescrypt_get_info, NULL, }; +#endif + +#ifdef HAVE_CRYPT_SM3 +static const php_password_algo xpass_algo_sm3crypt = { + "sm3crypt", + php_xpass_sm3crypt_hash, + php_xpass_verify, + php_xpass_needs_rehash, + NULL, // php_xpass_yescrypt_get_info, + NULL, +}; + +static const php_password_algo xpass_algo_sm3yescrypt = { + "sm3yescrypt", + php_xpass_sm3yescrypt_hash, + php_xpass_verify, + php_xpass_needs_rehash, + NULL, // php_xpass_yescrypt_get_info, + NULL, +}; +#endif /* {{{ Generates a salt for algo */ PHP_FUNCTION(crypt_gensalt) @@ -203,17 +246,25 @@ 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; + if (SUCCESS == php_password_algo_register("6", &xpass_algo_sha512)) { + REGISTER_STRING_CONSTANT("PASSWORD_SHA512", "6", CONST_CS | CONST_PERSISTENT); } - REGISTER_STRING_CONSTANT("PASSWORD_SHA512", "6", CONST_CS | CONST_PERSISTENT); #endif #ifdef HAVE_CRYPT_YESCRYPT - if (FAILURE == php_password_algo_register("y", &xpass_algo_yescrypt)) { - return FAILURE; + if (SUCCESS == php_password_algo_register("y", &xpass_algo_yescrypt)) { + REGISTER_STRING_CONSTANT("PASSWORD_YESCRYPT", "y", CONST_CS | CONST_PERSISTENT); + } +#endif + +#ifdef HAVE_CRYPT_SM3 + if (SUCCESS == php_password_algo_register("sm3", &xpass_algo_sm3crypt)) { + REGISTER_STRING_CONSTANT("PASSWORD_SM3CRYPT", "sm3", CONST_CS | CONST_PERSISTENT); + } + + if (SUCCESS == php_password_algo_register("sm3y", &xpass_algo_sm3yescrypt)) { + REGISTER_STRING_CONSTANT("PASSWORD_SM3_YESCRYPT", "sm3y", CONST_CS | CONST_PERSISTENT); } - REGISTER_STRING_CONSTANT("PASSWORD_YESCRYPT", "y", CONST_CS | CONST_PERSISTENT); #endif return SUCCESS; diff --git a/xpass.stub.php b/xpass.stub.php index 68718da..18a0b68 100644 --- a/xpass.stub.php +++ b/xpass.stub.php @@ -24,6 +24,12 @@ const CRYPT_PREFIX_SCRYPT = '$7$'; const CRYPT_PREFIX_GOST_YESCRYPT = '$gy$'; /** @var string */ const CRYPT_PREFIX_YESCRYPT = '$y$'; +#ifdef HAVE_CRYPT_SM3 +/** @var string */ +const CRYPT_PREFIX_SM3CRYPT = '$sm3$'; +/** @var string */ +const CRYPT_PREFIX_SM3_YESCRYPT = '$sm3y$'; +#endif /** * @var int diff --git a/xpass_arginfo.h b/xpass_arginfo.h index f530d0f..b3f3e1c 100644 --- a/xpass_arginfo.h +++ b/xpass_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 9f75db3279543b07de6b59e720e8521694200a7c */ + * Stub hash: d778eda3c6fd835a9215bde896fbb0c3917c1893 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_crypt_gensalt, 0, 0, IS_STRING, 1) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, prefix, IS_STRING, 1, "null") @@ -35,6 +35,12 @@ static void register_xpass_symbols(int module_number) 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); +#if defined(HAVE_CRYPT_SM3) + REGISTER_STRING_CONSTANT("CRYPT_PREFIX_SM3CRYPT", "$sm3$", CONST_PERSISTENT); +#endif +#if defined(HAVE_CRYPT_SM3) + REGISTER_STRING_CONSTANT("CRYPT_PREFIX_SM3_YESCRYPT", "$sm3y$", CONST_PERSISTENT); +#endif 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); |
