Skip to content

Use php_random_bytes() for uniqid() #2123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions ext/standard/uniqid.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,26 @@
#include <sys/time.h>
#endif

#include "php_lcg.h"
#include "php_random.h"
#include "uniqid.h"

#define UNIQID_RAND_CHARS 10

static char convtab[] = "0123456789abcdefghijklmnopqrstuv";

/* {{{ proto string uniqid([string prefix [, bool more_entropy]])
Generates a unique ID */
#ifdef HAVE_GETTIMEOFDAY
PHP_FUNCTION(uniqid)
{
char *prefix = "";
#if defined(__CYGWIN__)
zend_bool more_entropy = 1;
#else
zend_bool more_entropy = 0;
#endif
zend_string *uniqid;
int sec, usec;
size_t prefix_len = 0;
struct timeval tv;
char bytes[UNIQID_RAND_CHARS*2];
int i, mask = (1 << 5) - 1;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "|sb", &prefix, &prefix_len,
&more_entropy)) {
Expand All @@ -72,12 +74,17 @@ PHP_FUNCTION(uniqid)
gettimeofday((struct timeval *) &tv, (struct timezone *) NULL);
sec = (int) tv.tv_sec;
usec = (int) (tv.tv_usec % 0x100000);
php_random_bytes(bytes, UNIQID_RAND_CHARS*2, 1);
for (i = 0; i < UNIQID_RAND_CHARS; i++) {
Copy link

@CarwynNelson CarwynNelson Sep 21, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm by no means knowledgeable on security (in fact I know almost nothing about it). But doesn't building up the uniqid like this (assuming that's what it's doing) open up a user to timing attacks?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EDIT: In other words shouldn't building up of the uniqid be done in constant time?

Copy link
Contributor Author

@yohgaki yohgaki Sep 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CarwynNelson
uniqid() produces timestamp based unique ID. This is what it supposed to do. (AFAIK, it was made for SMTP's message ID which uses timestamp based ID)
"more entropy" option should do better job. This RFC improves "more entropy" option by replacing php_combined_lcg() to php_random_bytes().

bytes[i] = convtab[bytes[i] & mask];
}
bytes[UNIQID_RAND_CHARS] = '\0';

/* The max value usec can have is 0xF423F, so we use only five hex
* digits for usecs.
*/
if (more_entropy) {
uniqid = strpprintf(0, "%s%08x%05x%.8F", prefix, sec, usec, php_combined_lcg() * 10);
uniqid = strpprintf(0, "%s%08x%05x%s", prefix, sec, usec, bytes);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can already see half the world breaking here...

Copy link
Contributor Author

@yohgaki yohgaki Sep 10, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ocramius
Why? It could break code, but almost all code does not care return value from uniqid() at all.
e.g. https://searchcode.com/?q=uniqid&loc=0&loc2=10000&lan=24

} else {
uniqid = strpprintf(0, "%s%08x%05x", prefix, sec, usec);
}
Expand Down