Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
nielsdos committed Oct 15, 2024
1 parent 2c2b2f3 commit 3c58e25
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 1 deletion.
13 changes: 13 additions & 0 deletions ext/standard/crypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,19 @@ PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const ch
return NULL;
}

if (salt[0] == '$' && (salt[1] == 'y' || salt[1] == '7') && salt[2] == '$') {
/* Reference yescrypt can handle NUL bytes in the password, but sytem crypt cannot.
* Return NULL for both cases for consistency. */
if (zend_char_has_nul_byte(password, (size_t) pass_len)) {
return NULL;
}

/* Neither reference yescrypt nor system crypt can handle NUL bytes in the salt. */
if (zend_char_has_nul_byte(salt, (size_t) salt_len)) {
return NULL;
}
}

/* Windows (win32/crypt) has a stripped down version of libxcrypt and
a CryptoApi md5_crypt implementation */
#if PHP_USE_PHP_CRYPT_R
Expand Down
11 changes: 11 additions & 0 deletions ext/standard/password.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,12 @@ const php_password_algo php_password_algo_bcrypt = {

/* yescrypt implementation */

static void php_password_yescrypt_expect_long(const char *parameter_name) {
if (!EG(exception)) {
zend_value_error("Parameter \"%s\" cannot be converted to int", parameter_name);
}
}

static zend_string *php_password_yescrypt_hash(const zend_string *password, zend_array *options) {
zend_long block_count = PHP_PASSWORD_YESCRYPT_DEFAULT_BLOCK_COUNT;
zend_long block_size = PHP_PASSWORD_YESCRYPT_DEFAULT_BLOCK_SIZE;
Expand All @@ -253,6 +259,7 @@ static zend_string *php_password_yescrypt_hash(const zend_string *password, zend
if (option) {
block_count = zval_try_get_long(option, &failed);
if (UNEXPECTED(failed)) {
php_password_yescrypt_expect_long("block_count");
return NULL;
}

Expand All @@ -266,6 +273,7 @@ static zend_string *php_password_yescrypt_hash(const zend_string *password, zend
if (option) {
block_size = zval_try_get_long(option, &failed);
if (UNEXPECTED(failed)) {
php_password_yescrypt_expect_long("block_size");
return NULL;
}

Expand All @@ -279,6 +287,7 @@ static zend_string *php_password_yescrypt_hash(const zend_string *password, zend
if (option) {
parallelism = zval_try_get_long(option, &failed);
if (UNEXPECTED(failed)) {
php_password_yescrypt_expect_long("parallelism");
return NULL;
}

Expand All @@ -292,6 +301,7 @@ static zend_string *php_password_yescrypt_hash(const zend_string *password, zend
if (option) {
time = zval_try_get_long(option, &failed);
if (UNEXPECTED(failed)) {
php_password_yescrypt_expect_long("time");
return NULL;
}

Expand Down Expand Up @@ -346,6 +356,7 @@ static zend_string *php_password_yescrypt_hash(const zend_string *password, zend

static bool php_password_yescrypt_valid(const zend_string *hash) {
const char *h = ZSTR_VAL(hash);
/* Note: $7$-style is longer */
return (ZSTR_LEN(hash) >= 3 /* "$y$" */ + 3 /* 3 parameters that must be encoded */ + 2 /* $salt$ */ + HASH_LEN
&& ZSTR_LEN(hash) <= PREFIX_LEN + 1 + HASH_LEN)
&& (h[0] == '$') && (h[1] == 'y' || h[1] == '7') && (h[2] == '$');
Expand Down
38 changes: 38 additions & 0 deletions ext/standard/tests/crypt/yescrypt.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
--TEST--
Test crypt() with yescrypt
--FILE--
<?php

var_dump(crypt("test", '$y$'));
var_dump(crypt("test", '$y$$'));
var_dump(crypt("test", '$y$j$'));
var_dump(crypt("test", '$y$j9$'));
var_dump(crypt("test\0x", '$y$j9T$salt'.chr(0)));
var_dump(crypt("test\0", '$y$j9T$salt'));
var_dump(crypt("test\0x", '$y$j9T$salt'));
var_dump(crypt("\0", '$y$j9T$salt'));

var_dump(crypt("test", '$y$j9T$'));
var_dump(crypt("test", '$y$j9T$salt'));
var_dump(crypt("test", '$y$j9T$salt$'));
var_dump(crypt("", '$y$j9T$salt'));

var_dump(crypt("", '$7$400.../....$'));
var_dump(crypt("", '$7$400.../....$salt$'));

?>
--EXPECT--
string(2) "*0"
string(2) "*0"
string(2) "*0"
string(2) "*0"
string(2) "*0"
string(2) "*0"
string(2) "*0"
string(2) "*0"
string(51) "$y$j9T$$6tN6tt5mmPHxQskcf5Oi7Sb.1nKYbi5cOZgTiMq7Qw4"
string(55) "$y$j9T$salt$a9CZafQyDF042zUCgPAhoF7Zd5phBweZqIIw6SMCTh."
string(55) "$y$j9T$salt$a9CZafQyDF042zUCgPAhoF7Zd5phBweZqIIw6SMCTh."
string(55) "$y$j9T$salt$sE5vvd.NbRw0CRzUgcEQ/PZMH4hmete7N5s3qN09F12"
string(58) "$7$400.../....$fsLd.toTUvgzSAYmoHbKwQGAmqLK6y.yIpW2WKuemOA"
string(63) "$7$400.../....$salt$3SJITk6BqtXkmuOQkPe7e.yClr8MVXc6twSB2ZBHPE3"
76 changes: 76 additions & 0 deletions ext/standard/tests/password/password_get_info_yescrypt.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
--TEST--
Test normal operation of password_get_info() with Yescrypt
--FILE--
<?php

var_dump(password_get_info('$y$jC5//$7NbMKtqBsR3PDV5JHBYPDtaRD3nRg/$FT4mgFH/6EJNHRAGvD6yvzGjCo01KpIhLwGbQW.Nxk1'));
var_dump(password_get_info('$y$jC50..$bBICnZqGiE5P5h4KjoYGpp4S773JB/$ZcD9FJW35.VG0kN0hh5C7oXa3o3dSBSXg/WDaTiWsA8'));
var_dump(password_get_info('$y$jA.0./$pU1KtJbSnMYKcNIQZZLPpAXFpZ4RB/$TeI5bGZQ5l589gWeUjaJzSlIPQZk7Wp2gLsnVG0gJH6'));

var_dump(password_get_info('$y$jA.0./$'));

echo "OK!";

?>
--EXPECT--
array(3) {
["algo"]=>
string(1) "y"
["algoName"]=>
string(8) "yescrypt"
["options"]=>
array(4) {
["block_count"]=>
int(32768)
["block_size"]=>
int(8)
["parallelism"]=>
int(1)
["time"]=>
int(2)
}
}
array(3) {
["algo"]=>
string(1) "y"
["algoName"]=>
string(8) "yescrypt"
["options"]=>
array(4) {
["block_count"]=>
int(32768)
["block_size"]=>
int(8)
["parallelism"]=>
int(2)
["time"]=>
int(1)
}
}
array(3) {
["algo"]=>
string(1) "y"
["algoName"]=>
string(8) "yescrypt"
["options"]=>
array(4) {
["block_count"]=>
int(8192)
["block_size"]=>
int(1)
["parallelism"]=>
int(2)
["time"]=>
int(2)
}
}
array(3) {
["algo"]=>
NULL
["algoName"]=>
string(7) "unknown"
["options"]=>
array(0) {
}
}
OK!
5 changes: 5 additions & 0 deletions ext/standard/tests/password/password_hash.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ Test normal operation of password_hash()

var_dump(password_hash("foo", PASSWORD_BCRYPT));

var_dump(password_hash("foo", PASSWORD_YESCRYPT));

$algos = [
PASSWORD_BCRYPT,
PASSWORD_YESCRYPT,
'2y',
1,
];
Expand All @@ -23,6 +26,8 @@ echo "OK!";
?>
--EXPECTF--
string(60) "$2y$12$%s"
string(81) "$y$j9T$%s"
bool(true)
bool(true)
bool(true)
bool(true)
Expand Down
69 changes: 69 additions & 0 deletions ext/standard/tests/password/password_hash_error_yescrypt.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
--TEST--
Test error operation of password_hash() with Yescrypt
--FILE--
<?php
try {
password_hash('test', PASSWORD_YESCRYPT, ['block_count' => 3]);
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
}

try {
password_hash('test', PASSWORD_YESCRYPT, ['block_count' => -1]);
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
}

try {
password_hash('test', PASSWORD_YESCRYPT, ['block_count' => []]);
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
}

try {
password_hash('test', PASSWORD_YESCRYPT, ['block_size' => 0]);
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
}

try {
password_hash('test', PASSWORD_YESCRYPT, ['block_size' => []]);
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
}

try {
password_hash('test', PASSWORD_YESCRYPT, ['parallelism' => 0]);
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
}

try {
password_hash('test', PASSWORD_YESCRYPT, ['parallelism' => []]);
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
}

try {
password_hash('test', PASSWORD_YESCRYPT, ['time' => -1]);
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
}

try {
password_hash('test', PASSWORD_YESCRYPT, ['time' => []]);
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
}

?>
--EXPECT--
Parameter "block_count" must be between 4 and 4294967295
Parameter "block_count" must be between 4 and 4294967295
Parameter "block_count" cannot be converted to int
Parameter "block_size" must be greater than 0
Parameter "block_size" cannot be converted to int
Parameter "parallelism" must be greater than 0
Parameter "parallelism" cannot be converted to int
Parameter "time" must be greater than or equal to 0
Parameter "time" cannot be converted to int
2 changes: 1 addition & 1 deletion ext/standard/tests/password/password_verify.phpt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
--TEST--
Test normal operation of password_verify)
Test normal operation of password_verify()
--FILE--
<?php
//-=-=-=-
Expand Down

0 comments on commit 3c58e25

Please sign in to comment.