mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Base structure for passsword_create and password_make_salt
This commit is contained in:
parent
d68b614b09
commit
c77f2c2958
6 changed files with 328 additions and 2 deletions
|
@ -1866,6 +1866,21 @@ ZEND_END_ARG_INFO()
|
|||
ZEND_BEGIN_ARG_INFO(arginfo_getlastmod, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
/* }}} */
|
||||
/* {{{ password.c */
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_password_create, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, password)
|
||||
ZEND_ARG_INFO(0, algo)
|
||||
ZEND_ARG_INFO(0, options)
|
||||
ZEND_END_ARG_INFO()
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_password_verify, 0, 0, 2)
|
||||
ZEND_ARG_INFO(0, password)
|
||||
ZEND_ARG_INFO(0, hash)
|
||||
ZEND_END_ARG_INFO()
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_password_make_salt, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, length)
|
||||
ZEND_ARG_INFO(0, raw_output)
|
||||
ZEND_END_ARG_INFO()
|
||||
/* }}} */
|
||||
/* {{{ proc_open.c */
|
||||
#ifdef PHP_CAN_SUPPORT_PROC_OPEN
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_proc_terminate, 0, 0, 1)
|
||||
|
@ -2880,6 +2895,10 @@ const zend_function_entry basic_functions[] = { /* {{{ */
|
|||
PHP_FE(base64_decode, arginfo_base64_decode)
|
||||
PHP_FE(base64_encode, arginfo_base64_encode)
|
||||
|
||||
PHP_FE(password_create, arginfo_password_create)
|
||||
PHP_FE(password_verify, arginfo_password_verify)
|
||||
PHP_FE(password_make_salt, arginfo_password_make_salt)
|
||||
|
||||
PHP_FE(convert_uuencode, arginfo_convert_uuencode)
|
||||
PHP_FE(convert_uudecode, arginfo_convert_uudecode)
|
||||
|
||||
|
@ -3630,6 +3649,7 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */
|
|||
BASIC_MINIT_SUBMODULE(browscap)
|
||||
BASIC_MINIT_SUBMODULE(standard_filters)
|
||||
BASIC_MINIT_SUBMODULE(user_filters)
|
||||
BASIC_MINIT_SUBMODULE(password)
|
||||
|
||||
#if defined(HAVE_LOCALECONV) && defined(ZTS)
|
||||
BASIC_MINIT_SUBMODULE(localeconv)
|
||||
|
|
|
@ -580,7 +580,7 @@ PHP_NEW_EXTENSION(standard, array.c base64.c basic_functions.c browscap.c crc32.
|
|||
incomplete_class.c url_scanner_ex.c ftp_fopen_wrapper.c \
|
||||
http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \
|
||||
var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \
|
||||
filters.c proc_open.c streamsfuncs.c http.c)
|
||||
filters.c proc_open.c streamsfuncs.c http.c password.c)
|
||||
|
||||
PHP_ADD_MAKEFILE_FRAGMENT
|
||||
PHP_INSTALL_HEADERS([ext/standard/])
|
||||
|
|
|
@ -19,7 +19,7 @@ EXTENSION("standard", "array.c base64.c basic_functions.c browscap.c \
|
|||
versioning.c assert.c strnatcmp.c levenshtein.c incomplete_class.c \
|
||||
url_scanner_ex.c ftp_fopen_wrapper.c http_fopen_wrapper.c \
|
||||
php_fopen_wrapper.c credits.c css.c var_unserializer.c ftok.c sha1.c \
|
||||
user_filters.c uuencode.c filters.c proc_open.c \
|
||||
user_filters.c uuencode.c filters.c proc_open.c password.c \
|
||||
streamsfuncs.c http.c flock_compat.c", false /* never shared */);
|
||||
PHP_INSTALL_HEADERS("", "ext/standard");
|
||||
if (PHP_MBREGEX != "no") {
|
||||
|
|
257
ext/standard/password.c
Normal file
257
ext/standard/password.c
Normal file
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2012 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| 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. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Anthony Ferrara <ircmaxell@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "php.h"
|
||||
#if HAVE_CRYPT
|
||||
#include "php_crypt.h"
|
||||
#endif
|
||||
|
||||
#include "php_password.h"
|
||||
#include "php_rand.h"
|
||||
#include "base64.h"
|
||||
|
||||
|
||||
PHP_MINIT_FUNCTION(password) /* {{{ */
|
||||
{
|
||||
REGISTER_STRING_CONSTANT("PASSWORD_DEFAULT", PHP_PASSWORD_DEFAULT, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_STRING_CONSTANT("PASSWORD_BCRYPT", PHP_PASSWORD_BCRYPT, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_STRING_CONSTANT("PASSWORD_MD5", PHP_PASSWORD_MD5, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_STRING_CONSTANT("PASSWORD_SHA256", PHP_PASSWORD_SHA256, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_STRING_CONSTANT("PASSWORD_SHA512", PHP_PASSWORD_SHA512, CONST_CS | CONST_PERSISTENT);
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
static int php_password_salt_is_alphabet(const char *str, const int len)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (!((str[i] >= 'A' && str[i] <= 'Z') || (str[i] >= 'a' && str[i] <= 'z') || (str[i] >= '0' && str[i] <= '9') || str[i] == '.' || str[i] == '/')) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int php_password_salt_to64(const char *str, const int str_len, const int out_len, char *ret)
|
||||
{
|
||||
int pos = 0;
|
||||
unsigned char *buffer;
|
||||
buffer = php_base64_encode((unsigned char*) str, str_len, NULL);
|
||||
for (pos = 0; pos < out_len; pos++) {
|
||||
if (buffer[pos] == '+') {
|
||||
ret[pos] = '.';
|
||||
} else if (buffer[pos] == '=') {
|
||||
efree(buffer);
|
||||
return FAILURE;
|
||||
} else {
|
||||
ret[pos] = buffer[pos];
|
||||
}
|
||||
}
|
||||
efree(buffer);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
static int php_password_make_salt(int length, int raw, char *ret)
|
||||
{
|
||||
int i, raw_length;
|
||||
char *buffer;
|
||||
if (raw) {
|
||||
raw_length = length;
|
||||
} else {
|
||||
raw_length = length * 3 / 4 + 1;
|
||||
}
|
||||
buffer = (char *) emalloc(raw_length + 1);
|
||||
|
||||
/* Temp Placeholder */
|
||||
for (i = 0; i < raw_length; i++) {
|
||||
buffer[i] = i;
|
||||
}
|
||||
/* /Temp Placeholder */
|
||||
|
||||
if (raw) {
|
||||
memcpy(ret, buffer, length);
|
||||
} else {
|
||||
char *result;
|
||||
result = emalloc(length + 1);
|
||||
if (php_password_salt_to64(buffer, raw_length, length, result) == FAILURE) {
|
||||
php_error_docref(NULL, E_WARNING, "Generated salt too short");
|
||||
efree(buffer);
|
||||
efree(result);
|
||||
return FAILURE;
|
||||
} else {
|
||||
memcpy(ret, result, length);
|
||||
efree(result);
|
||||
}
|
||||
}
|
||||
efree(buffer);
|
||||
ret[length] = 0;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
PHP_FUNCTION(password_verify)
|
||||
{
|
||||
}
|
||||
|
||||
PHP_FUNCTION(password_make_salt)
|
||||
{
|
||||
char *salt;
|
||||
int length = 0;
|
||||
zend_bool raw_output = 0;
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|b", &length, &raw_output) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
if (length <= 0) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length cannot be less than or equal zero: %d", length);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
salt = emalloc(length + 1);
|
||||
if (php_password_make_salt(length, (int) raw_output, salt) == FAILURE) {
|
||||
efree(salt);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
RETURN_STRINGL(salt, length, 0);
|
||||
}
|
||||
|
||||
|
||||
/* {{{ proto string password(string password, string algo = PASSWORD_DEFAULT, array options = array())
|
||||
Hash a password */
|
||||
PHP_FUNCTION(password_create)
|
||||
{
|
||||
char *password, *algo = 0, *hash_format, *hash, *salt;
|
||||
int password_len, algo_len = 0, salt_len = 0, required_salt_len = 0, hash_format_len;
|
||||
HashTable *options = 0;
|
||||
zval **option_buffer;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|sH", &password, &password_len, &algo, &algo_len, &options) == FAILURE) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (algo_len == 0) {
|
||||
algo = PHP_PASSWORD_DEFAULT;
|
||||
algo_len = strlen(PHP_PASSWORD_DEFAULT);
|
||||
}
|
||||
|
||||
if (strcmp(algo, PHP_PASSWORD_BCRYPT) == 0) {
|
||||
int cost = PHP_PASSWORD_BCRYPT_DEFAULT_COST;
|
||||
if (options && zend_symtable_find(options, "cost", 5, (void **) &option_buffer) == SUCCESS) {
|
||||
convert_to_long_ex(option_buffer);
|
||||
cost = Z_LVAL_PP(option_buffer);
|
||||
zval_ptr_dtor(option_buffer);
|
||||
if (cost < 4 || cost > 31) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid bcrypt cost parameter specified: %d", cost);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
required_salt_len = 22;
|
||||
hash_format = emalloc(8);
|
||||
sprintf(hash_format, "$2y$%02d$", cost);
|
||||
hash_format_len = 7;
|
||||
} else if (strcmp(algo, PHP_PASSWORD_MD5) == 0) {
|
||||
required_salt_len = 12;
|
||||
hash_format = emalloc(4);
|
||||
memcpy(hash_format, "$1$", 3);
|
||||
hash_format_len = 3;
|
||||
} else if (strcmp(algo, PHP_PASSWORD_SHA256) == 0 || strcmp(algo, PHP_PASSWORD_SHA512) == 0) {
|
||||
int rounds = PHP_PASSWORD_SHA_DEFAULT_ROUNDS;
|
||||
if (options && zend_symtable_find(options, "rounds", 7, (void **) &option_buffer) == SUCCESS) {
|
||||
convert_to_long_ex(option_buffer);
|
||||
rounds = Z_LVAL_PP(option_buffer);
|
||||
zval_ptr_dtor(option_buffer);
|
||||
if (rounds < 1000 || rounds > 999999999) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid SHA rounds parameter specified: %d", rounds);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
required_salt_len = 16;
|
||||
hash_format = emalloc(21);
|
||||
sprintf(hash_format, "$%s$rounds=%d$", algo, rounds);
|
||||
hash_format_len = strlen(hash_format);
|
||||
} else {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown password hashing algorithm: %s", algo);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (options && zend_symtable_find(options, "salt", 5, (void**) &option_buffer) == SUCCESS) {
|
||||
char *buffer;
|
||||
int buffer_len;
|
||||
if (Z_TYPE_PP(option_buffer) == IS_STRING) {
|
||||
buffer = Z_STRVAL_PP(option_buffer);
|
||||
buffer_len = Z_STRLEN_PP(option_buffer);
|
||||
} else {
|
||||
zval_ptr_dtor(option_buffer);
|
||||
efree(hash_format);
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Non-string salt parameter supplied");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
if (buffer_len < required_salt_len) {
|
||||
efree(hash_format);
|
||||
zval_ptr_dtor(option_buffer);
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Provided salt is too short: %d expecting %d", buffer_len, required_salt_len);
|
||||
RETURN_FALSE;
|
||||
} else if (0 == php_password_salt_is_alphabet(buffer, buffer_len)) {
|
||||
salt = emalloc(required_salt_len + 1);
|
||||
if (php_password_salt_to64(buffer, buffer_len, required_salt_len, salt) == FAILURE) {
|
||||
efree(hash_format);
|
||||
zval_ptr_dtor(option_buffer);
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Provided salt is too short: %d", salt_len);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
salt_len = required_salt_len;
|
||||
} else {
|
||||
salt = emalloc(required_salt_len + 1);
|
||||
memcpy(salt, buffer, required_salt_len);
|
||||
salt_len = required_salt_len;
|
||||
}
|
||||
zval_ptr_dtor(option_buffer);
|
||||
} else {
|
||||
salt = emalloc(required_salt_len + 1);
|
||||
if (php_password_make_salt(required_salt_len, 0, salt) == FAILURE) {
|
||||
efree(hash_format);
|
||||
efree(salt);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
salt_len = required_salt_len;
|
||||
}
|
||||
|
||||
salt[salt_len] = 0;
|
||||
|
||||
hash = emalloc(salt_len + hash_format_len + 1);
|
||||
sprintf(hash, "%s%s", hash_format, salt);
|
||||
hash[hash_format_len + salt_len] = 0;
|
||||
efree(hash_format);
|
||||
efree(salt);
|
||||
|
||||
RETURN_STRINGL(hash, hash_format_len + salt_len, 0);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
* vim600: sw=4 ts=4 fdm=marker
|
||||
* vim<600: sw=4 ts=4
|
||||
*/
|
48
ext/standard/php_password.h
Normal file
48
ext/standard/php_password.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2012 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.01 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_01.txt |
|
||||
| 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. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Anthony Ferrara <ircmaxell@php.net> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
/* $Id$ */
|
||||
|
||||
#ifndef PHP_PASSWORD_H
|
||||
#define PHP_PASSWORD_H
|
||||
|
||||
PHP_FUNCTION(password_create);
|
||||
PHP_FUNCTION(password_verify);
|
||||
PHP_FUNCTION(password_make_salt);
|
||||
|
||||
PHP_MINIT_FUNCTION(password);
|
||||
|
||||
#define PHP_PASSWORD_DEFAULT "2y"
|
||||
#define PHP_PASSWORD_BCRYPT "2y"
|
||||
#define PHP_PASSWORD_MD5 "1"
|
||||
#define PHP_PASSWORD_SHA256 "5"
|
||||
#define PHP_PASSWORD_SHA512 "6"
|
||||
|
||||
#define PHP_PASSWORD_BCRYPT_DEFAULT_COST 14;
|
||||
#define PHP_PASSWORD_SHA_DEFAULT_ROUNDS 5000;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
* c-basic-offset: 4
|
||||
* End:
|
||||
*/
|
|
@ -58,6 +58,7 @@
|
|||
#include "php_versioning.h"
|
||||
#include "php_ftok.h"
|
||||
#include "php_type.h"
|
||||
#include "php_password.h"
|
||||
|
||||
#define phpext_standard_ptr basic_functions_module_ptr
|
||||
PHP_MINIT_FUNCTION(standard_filters);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue