Skip to content

Conversation

paragonie-scott
Copy link
Contributor

Enhancements for random_bytes(). cc @SammyK @ircmaxell @lt

@KalleZ
Copy link
Member

KalleZ commented Sep 9, 2015

Hi

Patch looks good, the only thing (minor) is the C++ comment but thats hardly worth mentioning (since we confront C89)

cc @SammyK @weltling @Tyrael

@paragonie-scott
Copy link
Contributor Author

You mean the // one? I can fix that too.

@@ -85,8 +89,29 @@ static int php_random_bytes(void *bytes, size_t size)
}
#elif HAVE_DECL_ARC4RANDOM_BUF
arc4random_buf(bytes, size);
#elif defined SYS_getrandom
/* Linux getrandom(2) syscall */
size_t read_bytes = 0;
Copy link
Member

Choose a reason for hiding this comment

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

Although we mainly do this on Windows, but declarations at first but I'm not sure there is any recent (and sane) compiler that will complain here, but not a biggie.

@KalleZ
Copy link
Member

KalleZ commented Sep 9, 2015

Yeha I mean the double slash, but else its fine. I added an inline comment note as well

@paragonie-scott
Copy link
Contributor Author

Okay, discussing this in room 11 and making a few tweaks. Will send a squashed commit as soon as the test pass locally.

@paragonie-scott
Copy link
Contributor Author

(Closed & reopened because Travis appeared to be sticking.)

@paragonie-scott
Copy link
Contributor Author

Oh hey, the tests passed. Neat. :)

@lt
Copy link
Contributor

lt commented Sep 9, 2015

Had getrandom(2) in originally and removed it for unremembered reasons. Probably due to lack of kernel support back then, but here we are in the future.

@paragonie-scott
Copy link
Contributor Author

The future is a wonderful place, indeed. :)

The original patch was just going to be checking the fstat result for sanity, but while I was here I implemented it too. :)

@paragonie-scott
Copy link
Contributor Author

All: The latest commit also removes /dev/arandom, for reasons outlined here.

@SammyK
Copy link
Contributor

SammyK commented Sep 9, 2015

Had getrandom(2) in originally and removed it for unremembered reasons.

Found the quote from @ircmaxell while discussing original RFC:

Another thought to avoid the file descriptor issue was in newer kernels just tie in the linux getrandom(2) syscall and BSD getentropy(2) syscall directly. But based on getentropy(2)'s docs it specifies that it's only meant to seed an arc4 generator, not provide a stream of bytes.

| | |
[#######=============] (we're going to write over the = region)
\\\\\\\\\\\\\
amount_to_read
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm digging the ascii art comments!

@ircmaxell
Copy link
Contributor

So apparently the 256 byte limit is about checking return results, and not a fundamental design limit. So +1 from me.

@paragonie-scott
Copy link
Contributor Author

(Travis was stuck.)

@nikic
Copy link
Member

nikic commented Sep 15, 2015

I've recently become aware of the fact that arc4random_buf on many operating systems (including current OSX) is still an actual RC4 generator (skipping some initial values), with potentially bad seeding at that. I'd suggest we drop this as well and only use getrandom or /dev/urandom.

@@ -30,6 +30,10 @@
#if PHP_WIN32
# include "win32/winutil.h"
#endif
#ifdef __linux__
# include <sys/syscall.h>
Copy link
Member

Choose a reason for hiding this comment

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

This header shouldn't be necessary anymore, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, I forgot to remove that.

@lt
Copy link
Contributor

lt commented Sep 15, 2015

I'm sure I read somewhere that OSX actually uses arc4random for urandom. Will have a quick look around to see if I can find evidence of that.

Aside from older BSDs which other OS are you aware of? (so we can research the truth there too)

@nikic
Copy link
Member

nikic commented Sep 15, 2015

@lt Wikipedia says:

In OpenBSD 5.5, released in May 2014, arc4random was modified to use ChaCha20.[13][14] As of January 2015, implementation of arc4random in NetBSD[15][16] also uses ChaCha20, however, implementation of arc4random in FreeBSD,[17] Linux's libbsd,[18] and Mac OS X[19] are still based on RC4.

And the OSX implementation was just turned up in my Twitter feed: https://opensource.apple.com/source/Libc/Libc-1044.10.1/gen/FreeBSD/arc4random.c

@lt
Copy link
Contributor

lt commented Sep 15, 2015

Discarding (at least) the initial 256 bytes mitigates the known biasing weaknesses in RC4 as far as I am aware. So is the only issue here the dodgy seeding?

@nikic
Copy link
Member

nikic commented Sep 15, 2015

@lt I'm not up to date on RC4 research, but as far as I remember multi-byte biases (unlike the single-byte ones) recur periodically and affect more than the first few bytes.

@paragonie-scott
Copy link
Contributor Author

The 256-byte issue with RC4 is for encrypting information as a stream cipher. It probably doesn't degrade the security of Fortuna implementations, especially since the kernel will reseed it frequently.

That said, there are still exploitable RC4 biases even after discarding the first N bytes of output. ChaCha20 should be the standard these days.

@paragonie-scott
Copy link
Contributor Author

The 1, 9 came from http://insanecoding.blogspot.com/2014/05/a-good-idea-with-bad-usage-devurandom.html and confirmed by ls -lah /dev | grep urandom.

Fix to_read, throw exception if syscall fails

Fixes thanks to feedback from sarnold at ##crypto on freenode

Correction on error conditions

Remove dead code (thanks @defuse)

It turns out getrandom can take >256, getentropy refuses.

Better semantics

Thanks @defuse for catching my silly mistake here

Cast to size_t to be explicit

Let's simplify the logic a bit

Let's be consistent; define everything before we do any logic

Continuously check that the file descriptor is still a valid one

Add device type check on fd initialization
}
#ifdef __linux__
// Make sure that /dev/urandom is the proper urandom device on Linux
if (st.st_rdev != makedev(1, 9)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't like hardcoding this. Does it come from some standard that /dev/urandom on Linux always must be the same? Why we need to check this anyway? If someone has permissions to mess with /dev to fool us, the system has way more problems than PHP could fix. Checking if the file has been opened successfully, e.g. to see if we aren't in broken chroot() env or broken permissions - that's fine, but beyond that I don't think we should bother, and especially hardcode device numbers inside the code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does it come from some standard that /dev/urandom on Linux always must be the same?

http://insanecoding.blogspot.co.uk/2014/05/a-good-idea-with-bad-usage-devurandom.html

The Linux user manual page for the random devices explicitly informs the reader of these magic numbers, so hopefully they won't change. I have no official sources for the magic numbers on the other OSs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm removing it for now. If this turns out to be a source for security issues down the line, I'd be surprised. But if it does, we can always look back and have a reference point for how to re-implement it.

@paragonie-scott
Copy link
Contributor Author

@jedisct1 made a similar argument against makedev in jedisct1/libsodium#300, and since newer kernels will just provide getrandom there's not much benefit in supporting these magic numbers.

@php-pulls
Copy link

Comment on behalf of ab at php.net:

Merged into 7.0.

Thanks.

@php-pulls
Copy link

Comment on behalf of ab at php.net:

and closed :)

@php-pulls php-pulls closed this Sep 29, 2015
@SammyK
Copy link
Contributor

SammyK commented Sep 29, 2015

🎉

@dragoonis
Copy link
Contributor

👍

@nikic
Copy link
Member

nikic commented Oct 5, 2015

Could you please take a look at https://bugs.php.net/bug.php?id=70641?

@jedisct1
Copy link
Contributor

jedisct1 commented Oct 5, 2015

Including linux/ headers is asking for trouble regarding portability across Linux distros.
You'd better use syscall(SYS_getrandom, ...) which only requires sys/syscall.h.

Also, regarding the file type check: jedisct1/libsodium#302 :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants