New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PR for Password Hash RFC #191
Changes from 40 commits
c77f2c2
7e41980
6574028
f7097d9
18d3bd9
618f262
41d7374
2d4b7cb
232da90
e505316
2b9591f
5f44be0
0dd2f16
6bb3865
da3d8bf
9e18e57
9c1445c
f53112f
6cc3c65
6943f2a
886527d
5160dc1
db86d54
ee7e799
9d3630b
99b7956
707c907
e05413c
824f1f4
db41f9f
e8b7f5b
e9a7bde
ebe0bd5
76f3295
3e383dc
7161c3d
7ec80e1
83cfff4
e034a46
44c2624
6fd5ba5
8bd79d1
4a7d18c
25b2d36
1751d5f
76e83f7
37b2207
0bc9ca3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -145,100 +145,54 @@ static void php_to64(char *s, long v, int n) /* {{{ */ | |
} | ||
/* }}} */ | ||
|
||
/* {{{ proto string crypt(string str [, string salt]) | ||
Hash a string */ | ||
PHP_FUNCTION(crypt) | ||
PHPAPI int php_crypt(const char *password, const int pass_len, const char *salt, int salt_len, char **result) | ||
{ | ||
char salt[PHP_MAX_SALT_LEN + 1]; | ||
char *str, *salt_in = NULL; | ||
int str_len, salt_in_len = 0; | ||
char *crypt_res; | ||
salt[0] = salt[PHP_MAX_SALT_LEN] = '\0'; | ||
|
||
/* 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 (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &salt_in, &salt_in_len) == FAILURE) { | ||
return; | ||
} | ||
|
||
if (salt_in) { | ||
memcpy(salt, salt_in, MIN(PHP_MAX_SALT_LEN, salt_in_len)); | ||
} | ||
|
||
/* The automatic salt generation covers standard DES, md5-crypt and Blowfish (simple) */ | ||
if (!*salt) { | ||
#if PHP_MD5_CRYPT | ||
strncpy(salt, "$1$", PHP_MAX_SALT_LEN); | ||
php_to64(&salt[3], PHP_CRYPT_RAND, 4); | ||
php_to64(&salt[7], PHP_CRYPT_RAND, 4); | ||
strncpy(&salt[11], "$", PHP_MAX_SALT_LEN - 11); | ||
#elif PHP_STD_DES_CRYPT | ||
php_to64(&salt[0], PHP_CRYPT_RAND, 2); | ||
salt[2] = '\0'; | ||
#endif | ||
salt_in_len = strlen(salt); | ||
} else { | ||
salt_in_len = MIN(PHP_MAX_SALT_LEN, salt_in_len); | ||
} | ||
|
||
/* Windows (win32/crypt) has a stripped down version of libxcrypt and | ||
a CryptoApi md5_crypt implementation */ | ||
#if PHP_USE_PHP_CRYPT_R | ||
{ | ||
struct php_crypt_extended_data buffer; | ||
|
||
if (salt[0]=='$' && salt[1]=='1' && salt[2]=='$') { | ||
char output[MD5_HASH_MAX_LEN]; | ||
char output[MD5_HASH_MAX_LEN], *out; | ||
|
||
RETURN_STRING(php_md5_crypt_r(str, salt, output), 1); | ||
out = php_md5_crypt_r(password, salt, output); | ||
if (out) { | ||
*result = estrdup(out); | ||
return SUCCESS; | ||
} | ||
return FAILURE; | ||
} else if (salt[0]=='$' && salt[1]=='6' && salt[2]=='$') { | ||
const char sha512_salt_prefix[] = "$6$"; | ||
const char sha512_rounds_prefix[] = "rounds="; | ||
char *output; | ||
int needed = (sizeof(sha512_salt_prefix) - 1 | ||
+ sizeof(sha512_rounds_prefix) + 9 + 1 | ||
+ salt_in_len + 1 + 86 + 1); | ||
output = emalloc(needed); | ||
salt[salt_in_len] = '\0'; | ||
output = emalloc(PHP_MAX_SALT_LEN); | ||
|
||
crypt_res = php_sha512_crypt_r(str, salt, output, needed); | ||
crypt_res = php_sha512_crypt_r(password, salt, output, PHP_MAX_SALT_LEN); | ||
if (!crypt_res) { | ||
if (salt[0]=='*' && salt[1]=='0') { | ||
RETVAL_STRING("*1", 1); | ||
} else { | ||
RETVAL_STRING("*0", 1); | ||
} | ||
memset(output, 0, PHP_MAX_SALT_LEN); | ||
efree(output); | ||
return FAILURE; | ||
} else { | ||
RETVAL_STRING(output, 1); | ||
*result = estrdup(output); | ||
memset(output, 0, PHP_MAX_SALT_LEN); | ||
efree(output); | ||
return SUCCESS; | ||
} | ||
|
||
memset(output, 0, needed); | ||
efree(output); | ||
} else if (salt[0]=='$' && salt[1]=='5' && salt[2]=='$') { | ||
const char sha256_salt_prefix[] = "$5$"; | ||
const char sha256_rounds_prefix[] = "rounds="; | ||
char *output; | ||
int needed = (sizeof(sha256_salt_prefix) - 1 | ||
+ sizeof(sha256_rounds_prefix) + 9 + 1 | ||
+ salt_in_len + 1 + 43 + 1); | ||
output = emalloc(needed); | ||
salt[salt_in_len] = '\0'; | ||
output = emalloc(PHP_MAX_SALT_LEN); | ||
|
||
crypt_res = php_sha256_crypt_r(str, salt, output, needed); | ||
crypt_res = php_sha256_crypt_r(password, salt, output, PHP_MAX_SALT_LEN); | ||
if (!crypt_res) { | ||
if (salt[0]=='*' && salt[1]=='0') { | ||
RETVAL_STRING("*1", 1); | ||
} else { | ||
RETVAL_STRING("*0", 1); | ||
} | ||
memset(output, 0, PHP_MAX_SALT_LEN); | ||
efree(output); | ||
return FAILURE; | ||
} else { | ||
RETVAL_STRING(output, 1); | ||
*result = estrdup(output); | ||
memset(output, 0, PHP_MAX_SALT_LEN); | ||
efree(output); | ||
return SUCCESS; | ||
} | ||
|
||
memset(output, 0, needed); | ||
efree(output); | ||
} else if ( | ||
salt[0] == '$' && | ||
salt[1] == '2' && | ||
|
@@ -251,31 +205,25 @@ PHP_FUNCTION(crypt) | |
|
||
memset(output, 0, PHP_MAX_SALT_LEN + 1); | ||
|
||
crypt_res = php_crypt_blowfish_rn(str, salt, output, sizeof(output)); | ||
crypt_res = php_crypt_blowfish_rn(password, salt, output, sizeof(output)); | ||
if (!crypt_res) { | ||
if (salt[0]=='*' && salt[1]=='0') { | ||
RETVAL_STRING("*1", 1); | ||
} else { | ||
RETVAL_STRING("*0", 1); | ||
} | ||
memset(output, 0, PHP_MAX_SALT_LEN + 1); | ||
return FAILURE; | ||
} else { | ||
RETVAL_STRING(output, 1); | ||
*result = estrdup(output); | ||
memset(output, 0, PHP_MAX_SALT_LEN + 1); | ||
return SUCCESS; | ||
} | ||
|
||
memset(output, 0, PHP_MAX_SALT_LEN + 1); | ||
} else { | ||
memset(&buffer, 0, sizeof(buffer)); | ||
_crypt_extended_init_r(); | ||
|
||
crypt_res = _crypt_extended_r(str, salt, &buffer); | ||
crypt_res = _crypt_extended_r(password, salt, &buffer); | ||
if (!crypt_res) { | ||
if (salt[0]=='*' && salt[1]=='0') { | ||
RETURN_STRING("*1", 1); | ||
} else { | ||
RETURN_STRING("*0", 1); | ||
} | ||
return FAILURE; | ||
} else { | ||
RETURN_STRING(crypt_res, 1); | ||
*result = estrdup(crypt_res); | ||
return SUCCESS; | ||
} | ||
} | ||
} | ||
|
@@ -291,21 +239,68 @@ PHP_FUNCTION(crypt) | |
# else | ||
# error Data struct used by crypt_r() is unknown. Please report. | ||
# endif | ||
crypt_res = crypt_r(str, salt, &buffer); | ||
crypt_res = crypt_r(password, salt, &buffer); | ||
if (!crypt_res) { | ||
if (salt[0]=='*' && salt[1]=='0') { | ||
RETURN_STRING("*1", 1); | ||
} else { | ||
RETURN_STRING("*0", 1); | ||
} | ||
return FAILURE; | ||
} else { | ||
RETURN_STRING(crypt_res, 1); | ||
*result = estrdup(crypt_res); | ||
return SUCCESS; | ||
} | ||
} | ||
# endif | ||
#endif | ||
} | ||
/* }}} */ | ||
|
||
|
||
/* {{{ proto string crypt(string str [, string salt]) | ||
Hash a string */ | ||
PHP_FUNCTION(crypt) | ||
{ | ||
char salt[PHP_MAX_SALT_LEN + 1]; | ||
char *str, *salt_in = NULL, *result = NULL; | ||
int str_len, salt_in_len = 0; | ||
salt[0] = salt[PHP_MAX_SALT_LEN] = '\0'; | ||
|
||
/* 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 (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &str, &str_len, &salt_in, &salt_in_len) == FAILURE) { | ||
return; | ||
} | ||
|
||
if (salt_in) { | ||
memcpy(salt, salt_in, MIN(PHP_MAX_SALT_LEN, salt_in_len)); | ||
} | ||
|
||
/* The automatic salt generation covers standard DES, md5-crypt and Blowfish (simple) */ | ||
if (!*salt) { | ||
#if PHP_MD5_CRYPT | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does that mean that my salt will change depending on the platform? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's core But now, the salt will not change (assuming that you're comment is ment for this line)... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, alright. Never mind :) |
||
strncpy(salt, "$1$", PHP_MAX_SALT_LEN); | ||
php_to64(&salt[3], PHP_CRYPT_RAND, 4); | ||
php_to64(&salt[7], PHP_CRYPT_RAND, 4); | ||
strncpy(&salt[11], "$", PHP_MAX_SALT_LEN - 11); | ||
#elif PHP_STD_DES_CRYPT | ||
php_to64(&salt[0], PHP_CRYPT_RAND, 2); | ||
salt[2] = '\0'; | ||
#endif | ||
salt_in_len = strlen(salt); | ||
} else { | ||
salt_in_len = MIN(PHP_MAX_SALT_LEN, salt_in_len); | ||
} | ||
salt[salt_in_len] = '\0'; | ||
|
||
if (php_crypt(str, str_len, salt, salt_in_len, &result) == FAILURE) { | ||
if (salt[0] == '*' && salt[1] == '0') { | ||
RETURN_STRING("*1", 1); | ||
} else { | ||
RETURN_STRING("*0", 1); | ||
} | ||
} | ||
RETURN_STRING(result, 0); | ||
} | ||
/* }}} */ | ||
#endif | ||
|
||
/* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here again the last arg should be 2 (as the algo is required too).