Comment by strenholme
5 days ago
Yes, /dev/(u)random is supposed to do that, but what if there’s a bug in a kernel (e.g. some embedded system which may not even be running Linux) which causes /dev/(u)ramdom to be less than secure? There’s also issues where, for example, it may no longer be possible to read /dev/(u)random after putting the process in a chroot() sandbox (chroot() isn’t defined in POSIX so its behavior is not guaranteed to be consistent across multiple operating systems).
getrandom() is often times suggested, but alas isn’t a standardized function, i.e. it’s not part of the POSIX specification. Considering how the C23 changes to the C specification caused a lot of perfectly good C code to no longer compile, I’m very anal about sticking to specs; I use '-std=C99' for my code these days (even though it can compile as C23 code) and stick to POSIX functions (except chroot() and setgroups(), but both of those predate POSIX, and even here I have a compile-time option to compile my code without those non-POSIX syscalls).
The code using a secure XOF (the algorithm was developed by the same team which later on made SHA-3, and includes people who helped make AES) has been around for nearly two decades (the code where I roll my own RNG to make secure random numbers has been around for over 25 years, but used AES before XOFs existed) and not one security problem has found with the RNG code has ever been found. [1] “Don’t roll your own RNG” is a suggestion, but it is possible to do so securely if one knows what they are doing (i.e. they have read Applied Cryptography and keep current with cryptographic developments).
For anything vibe coded (my code is 100% human written, for the record), rolling one’s own RNG is a really bad idea.
[1] There was a theoretical issue with cache timing attacks over two decades ago, so I put mitigations in place, and then chose to use an XOF for newer code.
[2] There was an issue where a separate implementation I made of this XOF would generate incorrect test vectors in clang, but only at some optimization levels. I now test the XOF in both GCC and clang at multiple optimization levels to make sure it acts correctly.
> getrandom() is often times suggested, but alas isn’t a standardized function
The POSIX standard function is getentropy(), which internally calls getrandom() on Linux.
> what if there’s a bug in the kernel which causes /dev/(u)ramdom to be less than secure?
It's often the other way around: the Linux kernel contains thousands of workarounds for buggy hardware, while the buggy hardware itself doesn't always get patched. Linux developers take this stuff very seriously. As a result it's often safer to rely on kernel APIs than to access the hardware directly.
The kernel code involving random number generation receives an exceptionally high amount of scrutiny because of its security implications, so I'd trust it to do the right thing over a naked call to RDRAND which nobody knows how exactly it's implemented in proprietary hardware or a handrolled solution to mix the RDRAND output with other entropy sources.
Remember the Debian openssl disaster from 2008? That happened exactly because someone had handrolled their entropy mixing solution, then someone else broke it.
From https://pubs.opengroup.org/onlinepubs/9799919799/functions/g...
“The intended use of this function is to create a seed for other pseudo-random number generators”
So, if I were to use genentropy() in a POSIX-compliant way, I would need to do what I already do: Use my own pseudo-random number generator.
The Debian openssl disaster (CVE 2008-0166, I remember it well) was caused because someone incorrectly patched secure code: Since the code used uninitialized memory as one of many entropy sources, which causes Valgrind to complain, they patched the code to not use uninitialized memory for entropy, but then accidentally disabled all other sources of entropy (except the 16-bit PID). It was caused because the person making the patch didn’t fully understand why it was a good idea to, in that context, use code which Valgrind complained about. [1]
As an aside, here’s how I deal with those Valgrind errors:
I do believe the Linux Kernel does have secure RNG code, but I also write code which has run on a lot of different systems and environments, including embedded ones, and some of them might not have a secure /dev/urandom.
[1] Debian has a lot of inflexible policies like this which can cause problems. Another issue Debian has is they have a policy a given piece of code must always compile to the same binary on a given architecture. That isn’t true with the unpatched version of my code, because the hash compression routine uses a 32-bit random number generated at compile time to avoid hash collision attacks (it also uses another 32-bit random number at runtime, and I make sure the hash compression values are never visible). So the Debian version of my code was forced to be patched to be less secure.
Uninitialized memory should never be used as source of entropy. Most release software these days compiles using hardening flags, which will (at some levels) replace uninitialized memory with sentinel values, making the entropy of uninitialized memory frequently around 0.
But it gets worse. If the optimizer sees that you're loading uninitialized memory, it can reason that since the result of uninitialized memory is garbage, doing any computation on that result is also garbage, and happily delete said computation as a result. The cascading effect of this is to delete all of the entropy-mixing code, leaving your entropy pool with only the very low entropy source--giving uninitialized memory effectively negative entropy.
The net effect is that, at least for me, seeing someone trying to seed an entropy pool with uninitialized memory is a giant neon flashing sign saying "do not trust this code." It provides at best very little entropy and at worst actively destroys entropy and has other calamitous effects like valgrind or sanitizer errors, so you need to have other entropy sources anyways, so why bother?
10 replies →
On modern systems, including Linux and OpenBSD, getentropy will return entropy seeded from not just rdrand/rdseed, but other entropy sources on the system, e.g. many Intel NICs, the AMD PSP, etc, and at least on Linux some well-vetted jitter hacks as a backstop for embedded devices without hardware RNGs. These sources are unavailable to user space. You have nothing to lose and everything to gain by using getentropy as one source, among whatever else you're using, to seed your PRNG.
> but what if there’s a bug in the kernel which causes /dev/(u)ramdom to be less than secure?
so instead you suggest trusting your own untested unlooked at implementation more?
Black-and-white thinking like this is always inaccurate.
>untested
The automated tests includes tests that make sure the XOF is correctly implemented. [1]
>unlooked at
People have been looking at my code for security holes for well over 20 years, and I have been getting multiple AI assisted security reports over the last year, things like “there’s a buffer overflow in this code which is nay to impossible to exploit, using code which hasn’t even been able to compile since 2022”.
[1] https://github.com/samboy/MaraDNS/tree/master/deadwood-githu... and https://github.com/samboy/MaraDNS/tree/master/deadwood-githu...
XOF correctly implemented doesn’t ensure you haven’t made other mistakes, such as using entropy sources correctly, doing needed math correctly to avoid any entropy bias, etc. etc….
You’re correct about black and white thinking. Then you invoke multiple straw men in this thread to defend that you’ll roll your own.
Disclaimer: I’ve been hired for multiple DoD projects to break hardware and software security systems, and I nearly always succeed, because so many people (and companies) roll their own.
8 replies →
No you see what we do, Is we ask Claude to make no mistakes in implementing the CSPRNG. This way we ensure there are no mistakes in the implementation or mathematics.
https://xkcd.com/221/
I know it’s a joke, but that code wouldn’t pass the DieHard tests. That’s actually one of the tests I did with the XOF I used, a test I ran over 16 years ago.
https://maradns.blogspot.com/2010/07/radiogatun32-passes-all...
> Yes, /dev/(u)random is supposed to do that, [...] getrandom() is often times suggested, but alas isn’t a standardized function, i.e. it’s not part of the POSIX specification.
Is /dev/random or /dev/urandom part of the POSIX specification?
Neither one is last time I looked. I’m a lot more uptight about POSIX compliance with code that needs to compile than I am with code that just needs a special /dev file to run, for the simple reason, when using POSIX during the compile stage, I can place the blame on GCC and/or clang if the program doesn’t compile when my program is POSIX and C99 compliant (I was, like many, burned by the C23 changes which made a lot of code which previously used to compile no longer compile).
I actually at one time had a Windows binary which would use Windows proprietary calls to make a “urandom” file (secret.txt was its name) so people could have good entropy on systems using the exact same interface as fopen("/dev/urandom","rb") (i.e fopen("secret.txt","rb")) without needing an actual /dev/urandom.
Refusing the platform's CSPRNG for such nonsense reasons is perhaps the dumbest form of POSIX worship. This is obviously an area where platform feature detection makes sense, there's no reason to follow a religion of standards adherence when it directly leads you into harm's way
Not POSIX/C99 worship as much as the very practical issue that a lot of C code which used to compile just fine stopped compiling once compilers defaulted to using C23. To use POSIX calls while compiling with -std=c99 (so I don’t have to update my code should C29 or what not come out) one needs to declare, for each .c file which uses a POSIX call, the version of POSIX the C file is compatible with.
i remember some linux kernel dev got ousted by the community because he/she wanted to not implement a backdoor that would compromise the results of /dev/urandom.
Who?
I have no idea about the claim of a backdoor. But here is the source:
Matt Mackall: "It's worth noting that the maintainer of record (me) for the Linux RNG quit the project about two years ago precisely because Linus decided to include a patch from Intel to allow their unauditable RdRand to bypass the entropy pool over my strenuous objections. "
https://cryptome.wikileaks.org/2013/07/intel-bed-nsa.htm?utm...
11 replies →