diff options
author | SammyK <sammyk@sammykmedia.com> | 2015-02-12 20:53:55 -0600 |
---|---|---|
committer | Nikita Popov <nikic@php.net> | 2015-05-09 21:57:50 +0200 |
commit | bc54d139aab546d90244504d92de288533477b0e (patch) | |
tree | 4b165f42c8b77b97e2540e767559f7a23cdddec1 | |
parent | 8f9f21e8d24c1b48dc271330e38f2931086c0c94 (diff) | |
download | php-git-bc54d139aab546d90244504d92de288533477b0e.tar.gz |
Initial implementation for CSPRNG API
-rw-r--r-- | ext/standard/basic_functions.c | 12 | ||||
-rw-r--r-- | ext/standard/config.m4 | 3 | ||||
-rw-r--r-- | ext/standard/config.w32 | 2 | ||||
-rw-r--r-- | ext/standard/php_random.h | 33 | ||||
-rw-r--r-- | ext/standard/php_standard.h | 1 | ||||
-rw-r--r-- | ext/standard/random.c | 158 |
6 files changed, 207 insertions, 2 deletions
diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 693ac4c8e3..916f8ef0a0 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -1905,6 +1905,15 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_mt_getrandmax, 0) ZEND_END_ARG_INFO() /* }}} */ +/* {{{ random.c */ +ZEND_BEGIN_ARG_INFO_EX(arginfo_random_bytes, 0, 0, 0) + ZEND_ARG_INFO(0, bytes) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_random_int, 0, 0, 0) + ZEND_ARG_INFO(0, max) +ZEND_END_ARG_INFO() +/* }}} */ /* {{{ sha1.c */ ZEND_BEGIN_ARG_INFO_EX(arginfo_sha1, 0, 0, 1) ZEND_ARG_INFO(0, str) @@ -2828,6 +2837,9 @@ const zend_function_entry basic_functions[] = { /* {{{ */ PHP_FE(mt_srand, arginfo_mt_srand) PHP_FE(mt_getrandmax, arginfo_mt_getrandmax) + PHP_FE(random_bytes, arginfo_random_bytes) + PHP_FE(random_int, arginfo_random_int) + #if HAVE_GETSERVBYNAME PHP_FE(getservbyname, arginfo_getservbyname) #endif diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index 3263389d00..a2c7a279f5 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -605,7 +605,8 @@ 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 password.c,,, + filters.c proc_open.c streamsfuncs.c http.c password.c \ + random.c,,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) PHP_ADD_MAKEFILE_FRAGMENT diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index e8b50efc7e..adff3d8c87 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -20,7 +20,7 @@ EXTENSION("standard", "array.c base64.c basic_functions.c browscap.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 password.c \ - streamsfuncs.c http.c flock_compat.c", false /* never shared */, + streamsfuncs.c http.c flock_compat.c random.c", false /* never shared */, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); PHP_INSTALL_HEADERS("", "ext/standard"); if (PHP_MBREGEX != "no") { diff --git a/ext/standard/php_random.h b/ext/standard/php_random.h new file mode 100644 index 0000000000..1be5894a63 --- /dev/null +++ b/ext/standard/php_random.h @@ -0,0 +1,33 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2015 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: Sammy Kaye Powers <me@sammyk.me> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef PHP_RANDOM_H +#define PHP_RANDOM_H + +PHP_FUNCTION(random_bytes); +PHP_FUNCTION(random_int); +#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 545406bef7..418350738a 100644 --- a/ext/standard/php_standard.h +++ b/ext/standard/php_standard.h @@ -59,6 +59,7 @@ #include "php_ftok.h" #include "php_type.h" #include "php_password.h" +#include "php_random.h" #include "php_version.h" #define PHP_STANDARD_VERSION PHP_VERSION diff --git a/ext/standard/random.c b/ext/standard/random.c new file mode 100644 index 0000000000..72377fec88 --- /dev/null +++ b/ext/standard/random.c @@ -0,0 +1,158 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 7 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2015 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: Sammy Kaye Powers <me@sammyk.me> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#include <stdlib.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <math.h> + +#include "php.h" + +#if PHP_WIN32 +# include "win32/winutil.h" +#endif + +// Big thanks to @ircmaxell for the help on this bit +union rand_long_buffer { + char buffer[8]; + long number; +}; + +// Copy/pasted from mcrypt.c +static int php_random_bytes(char *bytes, zend_long size) +{ + int n = 0; + +#if PHP_WIN32 + /* random/urandom equivalent on Windows */ + BYTE *win_bytes = (BYTE *) bytes; + if (php_win32_get_random_bytes(win_bytes, (size_t) size) == FAILURE) { + php_error_docref(NULL, E_WARNING, "Could not gather sufficient random data"); + return FAILURE; + } + n = (int)size; +#else + // @todo Need to cache the fd for random_int() call within loop + int fd; + size_t read_bytes = 0; + + fd = open("/dev/urandom", O_RDONLY); + if (fd < 0) { + php_error_docref(NULL, E_WARNING, "Cannot open source device"); + return FAILURE; + } + while (read_bytes < size) { + n = read(fd, bytes + read_bytes, size - read_bytes); + if (n < 0) { + break; + } + read_bytes += n; + } + n = read_bytes; + + close(fd); + if (n < size) { + php_error_docref(NULL, E_WARNING, "Could not gather sufficient random data"); + return FAILURE; + } +#endif + + // @todo - Do we need to do this? + bytes[size] = '\0'; + + return SUCCESS; +} + +/* {{{ proto string random_bytes(int bytes) +Return an arbitrary length of pseudo-random bytes as binary string */ +PHP_FUNCTION(random_bytes) +{ + zend_long size; + zend_string *bytes; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &size) == FAILURE) { + return; + } + + if (size <= 0 || size >= INT_MAX) { + php_error_docref(NULL, E_WARNING, "Cannot genrate a random string with a size of less than 1 or greater than %d", INT_MAX); + RETURN_FALSE; + } + + bytes = zend_string_alloc(size, 0); + + if (php_random_bytes(bytes->val, size) == FAILURE) { + zend_string_release(bytes); + return; + } + + RETURN_STR(bytes); +} +/* }}} */ + +/* {{{ proto int random_int(int maximum) +Return an arbitrary pseudo-random integer */ +PHP_FUNCTION(random_int) +{ + zend_long maximum; + zend_long size; + size_t i; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &maximum) == FAILURE) { + return; + } + + if (ZEND_NUM_ARGS() == 0) { + maximum = INT_MAX; + } + + if (maximum <= 0 || maximum > INT_MAX) { + php_error_docref(NULL, E_WARNING, "Cannot use maximum less than 1 or greater than %d", INT_MAX); + RETURN_FALSE; + } + + long range = (long) maximum; // @todo Support min? + + // Big thanks to @ircmaxell for the help on this bit + union rand_long_buffer value; + long result; + int bits = (int) (log((double) range) / log(2.0)) + 1; + int bytes = MAX(ceil(bits / 8), 1); + long mask = (long) pow(2.0, (double) bits) - 1; + + do { + if (php_random_bytes(&value.buffer, 8) == FAILURE) { + return; + } + result = value.number & mask; + } while (result > maximum); + + RETURN_LONG(result); +} +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ |