Commit: c77f2c29585f97bd9dad533b9d2bc8334de34f1b
Author: Anthony Ferrara <ircmax...@ircmaxell.com> Sun, 24 Jun 2012
22:44:43 -0400
Parents: d68b614b09b984e915db50b72430db4e4731480c
Branches: master
Link:
http://git.php.net/?p=php-src.git;a=commitdiff;h=c77f2c29585f97bd9dad533b9d2bc8334de34f1b
Log:
Base structure for passsword_create and password_make_salt
Changed paths:
M ext/standard/basic_functions.c
M ext/standard/config.m4
M ext/standard/config.w32
A ext/standard/password.c
A ext/standard/php_password.h
M ext/standard/php_standard.h
diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c
index 63d40ef..64025db 100644
--- a/ext/standard/basic_functions.c
+++ b/ext/standard/basic_functions.c
@@ -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)
diff --git a/ext/standard/config.m4 b/ext/standard/config.m4
index c33ae1e..fba423b 100644
--- a/ext/standard/config.m4
+++ b/ext/standard/config.m4
@@ -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/])
diff --git a/ext/standard/config.w32 b/ext/standard/config.w32
index d14b859..5f24641b 100644
--- a/ext/standard/config.w32
+++ b/ext/standard/config.w32
@@ -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") {
diff --git a/ext/standard/password.c b/ext/standard/password.c
new file mode 100644
index 0000000..677f132
--- /dev/null
+++ b/ext/standard/password.c
@@ -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 |
+ | lice...@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Anthony Ferrara <ircmax...@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
+ */
diff --git a/ext/standard/php_password.h b/ext/standard/php_password.h
new file mode 100644
index 0000000..f813189
--- /dev/null
+++ b/ext/standard/php_password.h
@@ -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 |
+ | lice...@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Anthony Ferrara <ircmax...@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:
+ */
diff --git a/ext/standard/php_standard.h b/ext/standard/php_standard.h
index 483dbc3..bccfebe 100644
--- a/ext/standard/php_standard.h
+++ b/ext/standard/php_standard.h
@@ -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);
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php