Skip to content

Commit 3c58e25

Browse files
committed
wip
1 parent 2c2b2f3 commit 3c58e25

File tree

7 files changed

+213
-1
lines changed

7 files changed

+213
-1
lines changed

ext/standard/crypt.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,19 @@ PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const ch
7777
return NULL;
7878
}
7979

80+
if (salt[0] == '$' && (salt[1] == 'y' || salt[1] == '7') && salt[2] == '$') {
81+
/* Reference yescrypt can handle NUL bytes in the password, but sytem crypt cannot.
82+
* Return NULL for both cases for consistency. */
83+
if (zend_char_has_nul_byte(password, (size_t) pass_len)) {
84+
return NULL;
85+
}
86+
87+
/* Neither reference yescrypt nor system crypt can handle NUL bytes in the salt. */
88+
if (zend_char_has_nul_byte(salt, (size_t) salt_len)) {
89+
return NULL;
90+
}
91+
}
92+
8093
/* Windows (win32/crypt) has a stripped down version of libxcrypt and
8194
a CryptoApi md5_crypt implementation */
8295
#if PHP_USE_PHP_CRYPT_R

ext/standard/password.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,12 @@ const php_password_algo php_password_algo_bcrypt = {
234234

235235
/* yescrypt implementation */
236236

237+
static void php_password_yescrypt_expect_long(const char *parameter_name) {
238+
if (!EG(exception)) {
239+
zend_value_error("Parameter \"%s\" cannot be converted to int", parameter_name);
240+
}
241+
}
242+
237243
static zend_string *php_password_yescrypt_hash(const zend_string *password, zend_array *options) {
238244
zend_long block_count = PHP_PASSWORD_YESCRYPT_DEFAULT_BLOCK_COUNT;
239245
zend_long block_size = PHP_PASSWORD_YESCRYPT_DEFAULT_BLOCK_SIZE;
@@ -253,6 +259,7 @@ static zend_string *php_password_yescrypt_hash(const zend_string *password, zend
253259
if (option) {
254260
block_count = zval_try_get_long(option, &failed);
255261
if (UNEXPECTED(failed)) {
262+
php_password_yescrypt_expect_long("block_count");
256263
return NULL;
257264
}
258265

@@ -266,6 +273,7 @@ static zend_string *php_password_yescrypt_hash(const zend_string *password, zend
266273
if (option) {
267274
block_size = zval_try_get_long(option, &failed);
268275
if (UNEXPECTED(failed)) {
276+
php_password_yescrypt_expect_long("block_size");
269277
return NULL;
270278
}
271279

@@ -279,6 +287,7 @@ static zend_string *php_password_yescrypt_hash(const zend_string *password, zend
279287
if (option) {
280288
parallelism = zval_try_get_long(option, &failed);
281289
if (UNEXPECTED(failed)) {
290+
php_password_yescrypt_expect_long("parallelism");
282291
return NULL;
283292
}
284293

@@ -292,6 +301,7 @@ static zend_string *php_password_yescrypt_hash(const zend_string *password, zend
292301
if (option) {
293302
time = zval_try_get_long(option, &failed);
294303
if (UNEXPECTED(failed)) {
304+
php_password_yescrypt_expect_long("time");
295305
return NULL;
296306
}
297307

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

347357
static bool php_password_yescrypt_valid(const zend_string *hash) {
348358
const char *h = ZSTR_VAL(hash);
359+
/* Note: $7$-style is longer */
349360
return (ZSTR_LEN(hash) >= 3 /* "$y$" */ + 3 /* 3 parameters that must be encoded */ + 2 /* $salt$ */ + HASH_LEN
350361
&& ZSTR_LEN(hash) <= PREFIX_LEN + 1 + HASH_LEN)
351362
&& (h[0] == '$') && (h[1] == 'y' || h[1] == '7') && (h[2] == '$');
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
Test crypt() with yescrypt
3+
--FILE--
4+
<?php
5+
6+
var_dump(crypt("test", '$y$'));
7+
var_dump(crypt("test", '$y$$'));
8+
var_dump(crypt("test", '$y$j$'));
9+
var_dump(crypt("test", '$y$j9$'));
10+
var_dump(crypt("test\0x", '$y$j9T$salt'.chr(0)));
11+
var_dump(crypt("test\0", '$y$j9T$salt'));
12+
var_dump(crypt("test\0x", '$y$j9T$salt'));
13+
var_dump(crypt("\0", '$y$j9T$salt'));
14+
15+
var_dump(crypt("test", '$y$j9T$'));
16+
var_dump(crypt("test", '$y$j9T$salt'));
17+
var_dump(crypt("test", '$y$j9T$salt$'));
18+
var_dump(crypt("", '$y$j9T$salt'));
19+
20+
var_dump(crypt("", '$7$400.../....$'));
21+
var_dump(crypt("", '$7$400.../....$salt$'));
22+
23+
?>
24+
--EXPECT--
25+
string(2) "*0"
26+
string(2) "*0"
27+
string(2) "*0"
28+
string(2) "*0"
29+
string(2) "*0"
30+
string(2) "*0"
31+
string(2) "*0"
32+
string(2) "*0"
33+
string(51) "$y$j9T$$6tN6tt5mmPHxQskcf5Oi7Sb.1nKYbi5cOZgTiMq7Qw4"
34+
string(55) "$y$j9T$salt$a9CZafQyDF042zUCgPAhoF7Zd5phBweZqIIw6SMCTh."
35+
string(55) "$y$j9T$salt$a9CZafQyDF042zUCgPAhoF7Zd5phBweZqIIw6SMCTh."
36+
string(55) "$y$j9T$salt$sE5vvd.NbRw0CRzUgcEQ/PZMH4hmete7N5s3qN09F12"
37+
string(58) "$7$400.../....$fsLd.toTUvgzSAYmoHbKwQGAmqLK6y.yIpW2WKuemOA"
38+
string(63) "$7$400.../....$salt$3SJITk6BqtXkmuOQkPe7e.yClr8MVXc6twSB2ZBHPE3"
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
--TEST--
2+
Test normal operation of password_get_info() with Yescrypt
3+
--FILE--
4+
<?php
5+
6+
var_dump(password_get_info('$y$jC5//$7NbMKtqBsR3PDV5JHBYPDtaRD3nRg/$FT4mgFH/6EJNHRAGvD6yvzGjCo01KpIhLwGbQW.Nxk1'));
7+
var_dump(password_get_info('$y$jC50..$bBICnZqGiE5P5h4KjoYGpp4S773JB/$ZcD9FJW35.VG0kN0hh5C7oXa3o3dSBSXg/WDaTiWsA8'));
8+
var_dump(password_get_info('$y$jA.0./$pU1KtJbSnMYKcNIQZZLPpAXFpZ4RB/$TeI5bGZQ5l589gWeUjaJzSlIPQZk7Wp2gLsnVG0gJH6'));
9+
10+
var_dump(password_get_info('$y$jA.0./$'));
11+
12+
echo "OK!";
13+
14+
?>
15+
--EXPECT--
16+
array(3) {
17+
["algo"]=>
18+
string(1) "y"
19+
["algoName"]=>
20+
string(8) "yescrypt"
21+
["options"]=>
22+
array(4) {
23+
["block_count"]=>
24+
int(32768)
25+
["block_size"]=>
26+
int(8)
27+
["parallelism"]=>
28+
int(1)
29+
["time"]=>
30+
int(2)
31+
}
32+
}
33+
array(3) {
34+
["algo"]=>
35+
string(1) "y"
36+
["algoName"]=>
37+
string(8) "yescrypt"
38+
["options"]=>
39+
array(4) {
40+
["block_count"]=>
41+
int(32768)
42+
["block_size"]=>
43+
int(8)
44+
["parallelism"]=>
45+
int(2)
46+
["time"]=>
47+
int(1)
48+
}
49+
}
50+
array(3) {
51+
["algo"]=>
52+
string(1) "y"
53+
["algoName"]=>
54+
string(8) "yescrypt"
55+
["options"]=>
56+
array(4) {
57+
["block_count"]=>
58+
int(8192)
59+
["block_size"]=>
60+
int(1)
61+
["parallelism"]=>
62+
int(2)
63+
["time"]=>
64+
int(2)
65+
}
66+
}
67+
array(3) {
68+
["algo"]=>
69+
NULL
70+
["algoName"]=>
71+
string(7) "unknown"
72+
["options"]=>
73+
array(0) {
74+
}
75+
}
76+
OK!

ext/standard/tests/password/password_hash.phpt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ Test normal operation of password_hash()
88

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

11+
var_dump(password_hash("foo", PASSWORD_YESCRYPT));
12+
1113
$algos = [
1214
PASSWORD_BCRYPT,
15+
PASSWORD_YESCRYPT,
1316
'2y',
1417
1,
1518
];
@@ -23,6 +26,8 @@ echo "OK!";
2326
?>
2427
--EXPECTF--
2528
string(60) "$2y$12$%s"
29+
string(81) "$y$j9T$%s"
30+
bool(true)
2631
bool(true)
2732
bool(true)
2833
bool(true)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
--TEST--
2+
Test error operation of password_hash() with Yescrypt
3+
--FILE--
4+
<?php
5+
try {
6+
password_hash('test', PASSWORD_YESCRYPT, ['block_count' => 3]);
7+
} catch (ValueError $exception) {
8+
echo $exception->getMessage() . "\n";
9+
}
10+
11+
try {
12+
password_hash('test', PASSWORD_YESCRYPT, ['block_count' => -1]);
13+
} catch (ValueError $exception) {
14+
echo $exception->getMessage() . "\n";
15+
}
16+
17+
try {
18+
password_hash('test', PASSWORD_YESCRYPT, ['block_count' => []]);
19+
} catch (ValueError $exception) {
20+
echo $exception->getMessage() . "\n";
21+
}
22+
23+
try {
24+
password_hash('test', PASSWORD_YESCRYPT, ['block_size' => 0]);
25+
} catch (ValueError $exception) {
26+
echo $exception->getMessage() . "\n";
27+
}
28+
29+
try {
30+
password_hash('test', PASSWORD_YESCRYPT, ['block_size' => []]);
31+
} catch (ValueError $exception) {
32+
echo $exception->getMessage() . "\n";
33+
}
34+
35+
try {
36+
password_hash('test', PASSWORD_YESCRYPT, ['parallelism' => 0]);
37+
} catch (ValueError $exception) {
38+
echo $exception->getMessage() . "\n";
39+
}
40+
41+
try {
42+
password_hash('test', PASSWORD_YESCRYPT, ['parallelism' => []]);
43+
} catch (ValueError $exception) {
44+
echo $exception->getMessage() . "\n";
45+
}
46+
47+
try {
48+
password_hash('test', PASSWORD_YESCRYPT, ['time' => -1]);
49+
} catch (ValueError $exception) {
50+
echo $exception->getMessage() . "\n";
51+
}
52+
53+
try {
54+
password_hash('test', PASSWORD_YESCRYPT, ['time' => []]);
55+
} catch (ValueError $exception) {
56+
echo $exception->getMessage() . "\n";
57+
}
58+
59+
?>
60+
--EXPECT--
61+
Parameter "block_count" must be between 4 and 4294967295
62+
Parameter "block_count" must be between 4 and 4294967295
63+
Parameter "block_count" cannot be converted to int
64+
Parameter "block_size" must be greater than 0
65+
Parameter "block_size" cannot be converted to int
66+
Parameter "parallelism" must be greater than 0
67+
Parameter "parallelism" cannot be converted to int
68+
Parameter "time" must be greater than or equal to 0
69+
Parameter "time" cannot be converted to int

ext/standard/tests/password/password_verify.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
Test normal operation of password_verify)
2+
Test normal operation of password_verify()
33
--FILE--
44
<?php
55
//-=-=-=-

0 commit comments

Comments
 (0)