Skip to content
Browse files

First hack of a basic cs_random_bytes() ripped off from mcrypt_create…

…_iv().
  • Loading branch information...
1 parent 2433225 commit d848648675c334ab0590850b6ae2969fc048d2d2 @tom-- committed
Showing with 97 additions and 1 deletion.
  1. +6 −0 ext/standard/basic_functions.c
  2. +2 −1 ext/standard/php_math.h
  3. +4 −0 ext/standard/php_rand.h
  4. +85 −0 ext/standard/rand.c
View
6 ext/standard/basic_functions.c
@@ -1922,6 +1922,11 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_mt_getrandmax, 0)
ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_cs_random_bytes, 0, 0, 1)
+ ZEND_ARG_INFO(0, size)
+ ZEND_ARG_INFO(0, is_strong_result)
+ZEND_END_ARG_INFO()
/* }}} */
/* {{{ sha1.c */
ZEND_BEGIN_ARG_INFO_EX(arginfo_sha1, 0, 0, 1)
@@ -2839,6 +2844,7 @@ const zend_function_entry basic_functions[] = { /* {{{ */
PHP_FE(mt_rand, arginfo_mt_rand)
PHP_FE(mt_srand, arginfo_mt_srand)
PHP_FE(mt_getrandmax, arginfo_mt_getrandmax)
+ PHP_FE(cs_random_bytes, arginfo_cs_random_bytes)
#if HAVE_GETSERVBYNAME
PHP_FE(getservbyname, arginfo_getservbyname)
View
3 ext/standard/php_math.h
@@ -13,7 +13,7 @@
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Jim Winstead <jimw@php.net> |
- | Stig Sæther Bakken <ssb@php.net> |
+ | Stig S�ther Bakken <ssb@php.net> |
+----------------------------------------------------------------------+
*/
@@ -50,6 +50,7 @@ PHP_FUNCTION(getrandmax);
PHP_FUNCTION(mt_srand);
PHP_FUNCTION(mt_rand);
PHP_FUNCTION(mt_getrandmax);
+PHP_FUNCTION(cs_random_bytes);
PHP_FUNCTION(abs);
PHP_FUNCTION(ceil);
PHP_FUNCTION(floor);
View
4 ext/standard/php_rand.h
@@ -57,4 +57,8 @@ PHPAPI long php_rand(TSRMLS_D);
PHPAPI void php_mt_srand(php_uint32 seed TSRMLS_DC);
PHPAPI php_uint32 php_mt_rand(TSRMLS_D);
+/* cs_random_bytes function: API to system CSPRNG */
+/* Limit number of bytes user may request */
+#define MAX_CS_BYTES 1024
+
#endif /* PHP_RAND_H */
View
85 ext/standard/rand.c
@@ -26,6 +26,7 @@
/* $Id: rand.c 306939 2011-01-01 02:19:59Z felipe $ */
#include <stdlib.h>
+#include <fcntl.h>
#include "php.h"
#include "php_math.h"
@@ -373,6 +374,90 @@ PHP_FUNCTION(mt_getrandmax)
}
/* }}} */
+/* {{{ proto string cs_random_bytes(integer length [, &bool returned_strong_result])
+ Returns a string of the length specified filled with random bytes */
+PHP_FUNCTION(cs_random_bytes)
+{
+ char *str;
+ long size;
+ int is_strong_result = 1;
+ int n = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &size, &is_strong_result) == FAILURE) {
+ return;
+ }
+
+ if (size <= 0) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length argument must be positive");
+ RETURN_FALSE;
+ }
+
+ if (size >= MAX_CS_BYTES) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length argument exceeds limit %d", MAX_CS_BYTES);
+ RETURN_FALSE;
+ }
+
+ str = ecalloc(size + 1, 1);
+
+#if PHP_WIN32
+ /* on Windows use php_win32_get_random_bytes to access CryptGenRandom*/
+ BYTE *str_b = (BYTE *) str;
+ if (php_win32_get_random_bytes(str_b, (size_t) size) == FAILURE){
+ efree(str);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not gather sufficient random data");
+ RETURN_FALSE;
+ }
+ n = size;
+#else
+ int fd;
+ size_t read_bytes = 0;
+
+ /* try reading from /dev/random */
+ fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ efree(str);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot open random device");
+ RETURN_FALSE;
+ }
+ while (read_bytes < size) {
+ n = read(fd, str + read_bytes, size - read_bytes);
+ if (n < 0) {
+ break;
+ }
+ read_bytes += n;
+ }
+ close(fd);
+
+ /* if not enough bytes, try reading from /dev/urandom on Linux this is enough to
+ */
+ if (read_bytes < size) {
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd >= 0) {
+ while (read_bytes < size) {
+ n = read(fd, str + read_bytes, size - read_bytes);
+ if (n < 0) {
+ break;
+ }
+ read_bytes += n;
+ /* since we got something, result is not strong CS random */
@tom-- Owner
tom-- added a note

You are right that it is not accurate in the terms of the Ptaceks' article. This used terms in use in the PHP internals email list at the time, which were based on the Linux man page.

Personally, I agree with the Ptaceks. In the process of working on this it became clear that only Linux has something weird like a blocking /dev/random. Every other OS (Windows, FreeBSD, OpenBSD, Solaris, OS X) offers only a urandom-like API and they have no consistent way, or no way at all, for the application to check if the entropy pool is exhausted. And, in the case of any web app, the distinction is irrelevant for all practical purposes. There are far easier ways to hack a web app than exploiting a depleted entropy pool.

The distinction between /dev/random and /dev/urandom is a Unix design wart. The man page doesn’t want to admit that, so it invents a security concern that doesn’t really exist.

Yes, that!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ is_strong_result = 0;
+ }
+ close(fd);
+ }
+ }
+
+ n = read_bytes;
+ close(fd);
+ if (n < size) {
+ efree(str);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not gather sufficient random data");
+ RETURN_FALSE;
+ }
+#endif
+ RETURN_STRINGL(str, n, 0);
+}
+/* }}} */
+
/*
* Local variables:
* tab-width: 4

0 comments on commit d848648

Please sign in to comment.
Something went wrong with that request. Please try again.