1999-04-22 00:25:57 +00:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2019-01-30 09:03:12 +00:00
| Copyright ( c ) The PHP Group |
1999-04-22 00:25:57 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2006-01-01 12:51:34 +00:00
| This source file is subject to version 3.01 of the PHP license , |
1999-07-16 13:13:16 +00:00
| that is bundled with this package in the file LICENSE , and is |
2003-06-10 20:04:29 +00:00
| available through the world - wide - web at the following url : |
2006-01-01 12:51:34 +00:00
| http : //www.php.net/license/3_01.txt |
1999-07-16 13:13:16 +00:00
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ php . net so we can mail you a copy immediately . |
1999-04-22 00:25:57 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2004-02-12 19:05:41 +00:00
| Authors : Stig Bakken < ssb @ php . net > |
2018-11-01 16:30:28 +00:00
| Zeev Suraski < zeev @ php . net > |
2002-02-28 08:29:35 +00:00
| Rasmus Lerdorf < rasmus @ php . net > |
2010-02-21 18:11:11 +00:00
| Pierre Joye < pierre @ php . net > |
1999-04-22 00:25:57 +00:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2007-11-05 12:44:52 +00:00
*/
1999-04-22 00:25:57 +00:00
# include <stdlib.h>
# include "php.h"
# if HAVE_UNISTD_H
# include <unistd.h>
# endif
2010-04-22 20:54:35 +00:00
# if PHP_USE_PHP_CRYPT_R
2008-07-28 11:50:35 +00:00
# include "php_crypt_r.h"
# include "crypt_freesec.h"
# else
# if HAVE_CRYPT_H
# if defined(CRYPT_R_GNU_SOURCE) && !defined(_GNU_SOURCE)
# define _GNU_SOURCE
# endif
# include <crypt.h>
# endif
1999-04-22 00:25:57 +00:00
# endif
# include <time.h>
# include <string.h>
2000-02-11 15:59:30 +00:00
# ifdef PHP_WIN32
1999-04-22 00:25:57 +00:00
# include <process.h>
# endif
1999-12-04 19:19:57 +00:00
# include "php_crypt.h"
2016-07-05 15:02:34 +00:00
# include "php_random.h"
1999-04-22 00:25:57 +00:00
2016-03-25 19:48:34 +00:00
/* sha512 crypt has the maximal salt length of 123 characters */
2009-12-09 00:20:14 +00:00
# define PHP_MAX_SALT_LEN 123
1999-04-22 00:25:57 +00:00
2015-01-09 16:18:33 +00:00
/* Used to check DES salts to ensure that they contain only valid characters */
# define IS_VALID_SALT_CHARACTER(c) (((c) >= '.' && (c) <= '9') || ((c) >= 'A' && (c) <= 'Z') || ((c) >= 'a' && (c) <= 'z'))
2007-11-05 12:44:52 +00:00
PHP_MINIT_FUNCTION ( crypt ) /* {{{ */
1999-04-22 00:25:57 +00:00
{
2014-08-25 17:24:55 +00:00
REGISTER_LONG_CONSTANT ( " CRYPT_SALT_LENGTH " , PHP_MAX_SALT_LEN , CONST_CS | CONST_PERSISTENT ) ;
2016-03-25 19:48:34 +00:00
REGISTER_LONG_CONSTANT ( " CRYPT_STD_DES " , 1 , CONST_CS | CONST_PERSISTENT ) ;
REGISTER_LONG_CONSTANT ( " CRYPT_EXT_DES " , 1 , CONST_CS | CONST_PERSISTENT ) ;
REGISTER_LONG_CONSTANT ( " CRYPT_MD5 " , 1 , CONST_CS | CONST_PERSISTENT ) ;
REGISTER_LONG_CONSTANT ( " CRYPT_BLOWFISH " , 1 , CONST_CS | CONST_PERSISTENT ) ;
REGISTER_LONG_CONSTANT ( " CRYPT_SHA256 " , 1 , CONST_CS | CONST_PERSISTENT ) ;
REGISTER_LONG_CONSTANT ( " CRYPT_SHA512 " , 1 , CONST_CS | CONST_PERSISTENT ) ;
2000-11-03 00:45:24 +00:00
2010-04-22 20:54:35 +00:00
# if PHP_USE_PHP_CRYPT_R
2008-07-28 11:50:35 +00:00
php_init_crypt_r ( ) ;
# endif
return SUCCESS ;
}
2008-08-19 15:14:46 +00:00
/* }}} */
2008-07-28 11:50:35 +00:00
2008-08-19 15:14:46 +00:00
PHP_MSHUTDOWN_FUNCTION ( crypt ) /* {{{ */
2008-07-28 11:50:35 +00:00
{
2010-04-22 20:54:35 +00:00
# if PHP_USE_PHP_CRYPT_R
2008-07-28 11:50:35 +00:00
php_shutdown_crypt_r ( ) ;
2008-08-19 15:14:46 +00:00
# endif
2008-07-28 11:50:35 +00:00
2001-05-06 16:54:27 +00:00
return SUCCESS ;
}
2007-11-05 12:44:52 +00:00
/* }}} */
2000-11-03 00:45:24 +00:00
1999-04-22 00:25:57 +00:00
static unsigned char itoa64 [ ] = " ./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz " ;
2016-07-07 14:32:38 +00:00
static void php_to64 ( char * s , int n ) /* { { { */
2001-09-16 20:49:57 +00:00
{
1999-04-22 00:25:57 +00:00
while ( - - n > = 0 ) {
2016-08-02 12:28:42 +00:00
* s = itoa64 [ * s & 0x3f ] ;
s + + ;
2007-11-05 12:44:52 +00:00
}
}
/* }}} */
1999-04-22 00:25:57 +00:00
2015-05-21 21:12:51 +00:00
PHPAPI zend_string * php_crypt ( const char * password , const int pass_len , const char * salt , int salt_len , zend_bool quiet )
1999-04-22 00:25:57 +00:00
{
2010-02-21 18:11:11 +00:00
char * crypt_res ;
2014-02-25 04:46:51 +00:00
zend_string * result ;
2020-06-24 10:20:05 +00:00
if ( salt [ 0 ] = = ' * ' & & ( salt [ 1 ] = = ' 0 ' | | salt [ 1 ] = = ' 1 ' ) ) {
return NULL ;
}
2015-01-03 09:22:58 +00:00
/* Windows (win32/crypt) has a stripped down version of libxcrypt and
2008-07-28 11:50:35 +00:00
a CryptoApi md5_crypt implementation */
# if PHP_USE_PHP_CRYPT_R
2006-11-30 15:59:53 +00:00
{
2008-07-28 11:50:35 +00:00
struct php_crypt_extended_data buffer ;
if ( salt [ 0 ] = = ' $ ' & & salt [ 1 ] = = ' 1 ' & & salt [ 2 ] = = ' $ ' ) {
2012-06-28 18:44:04 +00:00
char output [ MD5_HASH_MAX_LEN ] , * out ;
out = php_md5_crypt_r ( password , salt , output ) ;
if ( out ) {
2014-08-25 17:24:55 +00:00
return zend_string_init ( out , strlen ( out ) , 0 ) ;
2012-06-28 18:44:04 +00:00
}
2014-02-25 04:46:51 +00:00
return NULL ;
2009-12-09 00:20:14 +00:00
} else if ( salt [ 0 ] = = ' $ ' & & salt [ 1 ] = = ' 6 ' & & salt [ 2 ] = = ' $ ' ) {
char * output ;
2012-06-29 15:32:25 +00:00
output = emalloc ( PHP_MAX_SALT_LEN ) ;
2009-12-09 00:20:14 +00:00
2012-06-29 15:32:25 +00:00
crypt_res = php_sha512_crypt_r ( password , salt , output , PHP_MAX_SALT_LEN ) ;
2010-02-21 18:11:11 +00:00
if ( ! crypt_res ) {
2016-10-15 16:55:44 +00:00
ZEND_SECURE_ZERO ( output , PHP_MAX_SALT_LEN ) ;
2012-06-28 18:44:04 +00:00
efree ( output ) ;
2014-02-25 04:46:51 +00:00
return NULL ;
2010-02-21 18:11:11 +00:00
} else {
2014-08-25 17:24:55 +00:00
result = zend_string_init ( output , strlen ( output ) , 0 ) ;
2016-10-15 16:55:44 +00:00
ZEND_SECURE_ZERO ( output , PHP_MAX_SALT_LEN ) ;
2012-06-29 15:32:25 +00:00
efree ( output ) ;
2014-02-25 04:46:51 +00:00
return result ;
2010-02-21 18:11:11 +00:00
}
2009-12-09 00:20:14 +00:00
} else if ( salt [ 0 ] = = ' $ ' & & salt [ 1 ] = = ' 5 ' & & salt [ 2 ] = = ' $ ' ) {
char * output ;
2012-06-29 15:32:25 +00:00
output = emalloc ( PHP_MAX_SALT_LEN ) ;
2009-12-09 00:20:14 +00:00
2012-06-29 15:32:25 +00:00
crypt_res = php_sha256_crypt_r ( password , salt , output , PHP_MAX_SALT_LEN ) ;
2010-02-21 18:11:11 +00:00
if ( ! crypt_res ) {
2016-10-15 16:55:44 +00:00
ZEND_SECURE_ZERO ( output , PHP_MAX_SALT_LEN ) ;
2012-06-28 18:44:04 +00:00
efree ( output ) ;
2014-02-25 04:46:51 +00:00
return NULL ;
2010-02-21 18:11:11 +00:00
} else {
2014-08-25 17:24:55 +00:00
result = zend_string_init ( output , strlen ( output ) , 0 ) ;
2016-10-15 16:55:44 +00:00
ZEND_SECURE_ZERO ( output , PHP_MAX_SALT_LEN ) ;
2012-06-29 15:32:25 +00:00
efree ( output ) ;
2014-02-25 04:46:51 +00:00
return result ;
2010-02-21 18:11:11 +00:00
}
2009-12-09 00:20:14 +00:00
} else if (
2008-07-28 11:50:35 +00:00
salt [ 0 ] = = ' $ ' & &
salt [ 1 ] = = ' 2 ' & &
2015-01-09 16:18:33 +00:00
salt [ 3 ] = = ' $ ' ) {
2008-07-28 11:50:35 +00:00
char output [ PHP_MAX_SALT_LEN + 1 ] ;
memset ( output , 0 , PHP_MAX_SALT_LEN + 1 ) ;
2012-06-28 18:44:04 +00:00
crypt_res = php_crypt_blowfish_rn ( password , salt , output , sizeof ( output ) ) ;
2010-02-21 18:11:11 +00:00
if ( ! crypt_res ) {
2014-09-18 23:46:14 +00:00
ZEND_SECURE_ZERO ( output , PHP_MAX_SALT_LEN + 1 ) ;
2014-02-25 04:46:51 +00:00
return NULL ;
2010-02-21 18:11:11 +00:00
} else {
2014-08-25 17:24:55 +00:00
result = zend_string_init ( output , strlen ( output ) , 0 ) ;
2014-09-18 23:46:14 +00:00
ZEND_SECURE_ZERO ( output , PHP_MAX_SALT_LEN + 1 ) ;
2014-02-25 04:46:51 +00:00
return result ;
2010-02-21 18:11:11 +00:00
}
2020-06-24 10:55:37 +00:00
} else if ( salt [ 0 ] = = ' _ '
| | ( IS_VALID_SALT_CHARACTER ( salt [ 0 ] ) & & IS_VALID_SALT_CHARACTER ( salt [ 1 ] ) ) ) {
2015-01-09 16:23:06 +00:00
/* DES Fallback */
2008-07-28 11:50:35 +00:00
memset ( & buffer , 0 , sizeof ( buffer ) ) ;
_crypt_extended_init_r ( ) ;
2010-02-21 18:11:11 +00:00
2019-06-19 11:48:20 +00:00
crypt_res = _crypt_extended_r ( ( const unsigned char * ) password , salt , & buffer ) ;
2014-10-07 11:27:57 +00:00
if ( ! crypt_res | | ( salt [ 0 ] = = ' * ' & & salt [ 1 ] = = ' 0 ' ) ) {
2014-02-25 04:46:51 +00:00
return NULL ;
2010-02-21 18:11:11 +00:00
} else {
2014-08-25 17:24:55 +00:00
result = zend_string_init ( crypt_res , strlen ( crypt_res ) , 0 ) ;
2014-02-25 04:46:51 +00:00
return result ;
2010-02-21 18:11:11 +00:00
}
2020-06-24 10:55:37 +00:00
} else {
/* Unknown hash type */
return NULL ;
2008-07-28 11:50:35 +00:00
}
}
# else
# if defined(HAVE_CRYPT_R) && (defined(_REENTRANT) || defined(_THREAD_SAFE))
{
# if defined(CRYPT_R_STRUCT_CRYPT_DATA)
2006-11-30 15:59:53 +00:00
struct crypt_data buffer ;
memset ( & buffer , 0 , sizeof ( buffer ) ) ;
2008-07-28 11:50:35 +00:00
# elif defined(CRYPT_R_CRYPTD)
2006-12-12 07:38:04 +00:00
CRYPTD buffer ;
2008-07-28 11:50:35 +00:00
# else
2016-03-25 19:18:46 +00:00
# error Data struct used by crypt_r() is unknown. Please report.
2008-07-28 11:50:35 +00:00
# endif
2012-06-28 18:44:04 +00:00
crypt_res = crypt_r ( password , salt , & buffer ) ;
2006-11-30 15:59:53 +00:00
}
2016-03-25 19:18:46 +00:00
# elif defined(HAVE_CRYPT)
crypt_res = crypt ( password , salt ) ;
# else
# error No crypt() implementation
2008-07-28 11:50:35 +00:00
# endif
2006-11-30 15:59:53 +00:00
# endif
2016-03-25 19:18:46 +00:00
if ( ! crypt_res | | ( salt [ 0 ] = = ' * ' & & salt [ 1 ] = = ' 0 ' ) ) {
2016-03-25 19:23:04 +00:00
return NULL ;
2016-03-25 19:18:46 +00:00
} else {
2016-03-25 19:23:04 +00:00
result = zend_string_init ( crypt_res , strlen ( crypt_res ) , 0 ) ;
return result ;
2016-03-25 19:18:46 +00:00
}
1999-04-22 00:25:57 +00:00
}
2000-05-17 19:40:10 +00:00
/* }}} */
2012-06-28 18:44:04 +00:00
/* {{{ proto string crypt(string str [, string salt])
Hash a string */
PHP_FUNCTION ( crypt )
{
char salt [ PHP_MAX_SALT_LEN + 1 ] ;
2014-02-25 04:46:51 +00:00
char * str , * salt_in = NULL ;
2014-08-27 13:31:48 +00:00
size_t str_len , salt_in_len = 0 ;
2014-02-25 04:46:51 +00:00
zend_string * result ;
2012-06-28 18:44:04 +00:00
2016-12-30 20:32:48 +00:00
ZEND_PARSE_PARAMETERS_START ( 1 , 2 )
Z_PARAM_STRING ( str , str_len )
Z_PARAM_OPTIONAL
Z_PARAM_STRING ( salt_in , salt_in_len )
ZEND_PARSE_PARAMETERS_END ( ) ;
2016-08-02 12:28:42 +00:00
2014-07-15 11:50:42 +00:00
salt [ 0 ] = salt [ PHP_MAX_SALT_LEN ] = ' \0 ' ;
2012-06-28 18:44:04 +00:00
/* 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 ) ;
if ( salt_in ) {
memcpy ( salt , salt_in , MIN ( PHP_MAX_SALT_LEN , salt_in_len ) ) ;
2013-10-29 09:53:45 +00:00
} else {
2014-12-13 22:06:14 +00:00
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. " ) ;
2012-06-28 18:44:04 +00:00
}
/* The automatic salt generation covers standard DES, md5-crypt and Blowfish (simple) */
if ( ! * salt ) {
2019-07-24 14:06:07 +00:00
memcpy ( salt , " $1$ " , 3 ) ;
2016-07-05 15:02:34 +00:00
php_random_bytes_throw ( & salt [ 3 ] , 8 ) ;
2016-07-07 14:32:38 +00:00
php_to64 ( & salt [ 3 ] , 8 ) ;
2012-06-28 18:44:04 +00:00
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 [ salt_in_len ] = ' \0 ' ;
2015-05-21 21:12:51 +00:00
if ( ( result = php_crypt ( str , ( int ) str_len , salt , ( int ) salt_in_len , 0 ) ) = = NULL ) {
2012-06-28 18:44:04 +00:00
if ( salt [ 0 ] = = ' * ' & & salt [ 1 ] = = ' 0 ' ) {
2014-02-13 13:54:23 +00:00
RETURN_STRING ( " *1 " ) ;
2012-06-28 18:44:04 +00:00
} else {
2014-02-13 13:54:23 +00:00
RETURN_STRING ( " *0 " ) ;
2012-06-28 18:44:04 +00:00
}
}
2014-02-25 04:46:51 +00:00
RETURN_STR ( result ) ;
2012-06-28 18:44:04 +00:00
}
/* }}} */