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

Reply via email to