]> granicus.if.org Git - php/commitdiff
Drop support for crypt() without explicit salt
authorNikita Popov <nikita.ppv@gmail.com>
Mon, 7 Sep 2020 13:43:26 +0000 (15:43 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 7 Sep 2020 13:43:26 +0000 (15:43 +0200)
crypt() without salt generates a weak $1$ MD5 hash. It has been
throwing a notice since 2013 and we provide a much better alternative
in password_hash() (which can auto-generate salts for strong
password hashes), so keeping this is just a liability.

UPGRADING
ext/standard/basic_functions.stub.php
ext/standard/basic_functions_arginfo.h
ext/standard/crypt.c
ext/standard/tests/strings/crypt.phpt

index d18bc98eeb0e5d4a26b8073cec7034afc81c63d4..0621d8eadee4115837ff4d3cb6e8c7895fbc31ec 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -576,6 +576,9 @@ PHP 8.0 UPGRADE NOTES
 
         $ctx = stream_context_create(['http' => ['protocol_version' => '1.0']]);
         echo file_get_contents('http://example.org', false, $ctx);
+  . Calling crypt() without an explicit salt is no longer supported. If you
+    would like to produce a strong hash with an auto-generated salt, use
+    password_hash() instead.
 
 - Sysvmsg:
   . msg_get_queue() will now return an SysvMessageQueue object rather than a
index 75819c7fb556b6efe395834cd110f419f0097eb2..44eb05a015f596df9c18b79eba0d98cd856057ef 100755 (executable)
@@ -391,7 +391,7 @@ function crc32(string $str): int {}
 
 /* crypt.c */
 
-function crypt(string $str, string $salt = UNKNOWN): string {}
+function crypt(string $str, string $salt): string {}
 
 /* datetime.c */
 
index 9d13b25b855bd10fa1d2e2932cea4ce587f93181..ef031e7afb7335f6f2fc9f932553cab043e1d008 100755 (executable)
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 010a6e0dee6d5e419e66eeefadd4dfabbbddfaca */
+ * Stub hash: 28da5d6df91403aad82b5872453053dc41076a6a */
 
 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)
@@ -597,7 +597,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_crc32, 0, 1, IS_LONG, 0)
        ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0)
 ZEND_END_ARG_INFO()
 
-ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_crypt, 0, 1, IS_STRING, 0)
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_crypt, 0, 2, IS_STRING, 0)
        ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0)
        ZEND_ARG_TYPE_INFO(0, salt, IS_STRING, 0)
 ZEND_END_ARG_INFO()
index f994ff4c31350e08649628eec95c3e0853fd6da5..8c105cf910e856cf6522985be8b4f64d13e6a3ab 100644 (file)
@@ -79,18 +79,6 @@ PHP_MSHUTDOWN_FUNCTION(crypt) /* {{{ */
 }
 /* }}} */
 
-static unsigned char itoa64[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
-/* Encode a string of bytes as Base64 */
-static void php_to64(char *s, int n) /* {{{ */
-{
-       while (--n >= 0) {
-               *s = itoa64[*s & 0x3f];
-               s++;
-       }
-}
-/* }}} */
-
 PHPAPI zend_string *php_crypt(const char *password, const int pass_len, const char *salt, int salt_len, zend_bool quiet)
 {
        char *crypt_res;
@@ -216,9 +204,8 @@ PHP_FUNCTION(crypt)
        size_t str_len, salt_in_len = 0;
        zend_string *result;
 
-       ZEND_PARSE_PARAMETERS_START(1, 2)
+       ZEND_PARSE_PARAMETERS_START(2, 2)
                Z_PARAM_STRING(str, str_len)
-               Z_PARAM_OPTIONAL
                Z_PARAM_STRING(salt_in, salt_in_len)
        ZEND_PARSE_PARAMETERS_END();
 
@@ -227,23 +214,9 @@ PHP_FUNCTION(crypt)
        /* This will produce suitable results if people depend on DES-encryption
         * available (passing always 2-character salt). At least for glibc6.1 */
        memset(&salt[1], '$', PHP_MAX_SALT_LEN - 1);
+       memcpy(salt, salt_in, MIN(PHP_MAX_SALT_LEN, salt_in_len));
 
-       if (salt_in) {
-               memcpy(salt, salt_in, MIN(PHP_MAX_SALT_LEN, salt_in_len));
-       } else {
-               php_error_docref(NULL, E_NOTICE, "No salt parameter was specified. You must use a randomly generated salt and a strong hash function to produce a secure hash.");
-       }
-
-       /* The automatic salt generation covers standard DES, md5-crypt and Blowfish (simple) */
-       if (!*salt) {
-               memcpy(salt, "$1$", 3);
-               php_random_bytes_throw(&salt[3], 8);
-               php_to64(&salt[3], 8);
-               strncpy(&salt[11], "$", PHP_MAX_SALT_LEN - 11);
-               salt_in_len = strlen(salt);
-       } else {
-               salt_in_len = MIN(PHP_MAX_SALT_LEN, salt_in_len);
-       }
+       salt_in_len = MIN(PHP_MAX_SALT_LEN, salt_in_len);
        salt[salt_in_len] = '\0';
 
        if ((result = php_crypt(str, (int)str_len, salt, (int)salt_in_len, 0)) == NULL) {
index 270f0372d13fd213a68d8fa51d0b3bae4576bff8..462aea8b59749c64a2d12eb1e7adb8c797a692d9 100644 (file)
@@ -18,14 +18,16 @@ echo (CRYPT_EXT_DES)  ? ((crypt($str, $salt2) === $res_2) ? 'EXT' : 'EXT - ERROR
 echo (CRYPT_MD5)      ? ((crypt($str, $salt3) === $res_3) ? 'MD5' : 'MD5 - ERROR') : 'MD5', "\n";
 echo (CRYPT_BLOWFISH) ? ((crypt($str, $salt4) === $res_4) ? 'BLO' : 'BLO - ERROR') : 'BLO', "\n";
 
-var_dump(crypt($str));
+try {
+    var_dump(crypt($str));
+} catch (ArgumentCountError $e) {
+    echo $e->getMessage(), "\n";
+}
 
 ?>
---EXPECTF--
+--EXPECT--
 STD
 EXT
 MD5
 BLO
-
-Notice: crypt(): No salt parameter was specified. You must use a randomly generated salt and a strong hash function to produce a secure hash. in %s on line %d
-string(%d) "%s"
+crypt() expects exactly 2 parameters, 1 given