Live data from Hacker News

Three mistakes from Dart/Flutter's weak PRNG

zellic.io

61–70 of 93 posts

Re: Three mistakes from Dart/Flutter's weak PRNG

#62
post #52

Earlier quoted context omitted.

"Useful entropy as a limited resource" is just an incorrect meme that has somehow brainwormed a significant fraction of engineers. Once that secure RNG is seeded, you're golden. Randomness is not depleted. Every mainstream OS is trivially capable of seeding the system secure RNG by the time userspace applications need to consume it. There is no availability / depletion problem for userspace.

That's absolutely not true, and some of us have directly experienced what happens when it runs out. There are implementations that will keep producing output without an ongoing and sufficient supply of fresh entropy, but there are also implementations that do not. Generally, those that do keep producing output in those cases are formally weaker. When the supply is treated conscientiously, depletion broadly doesn't ma…

No, you are mistaken, as were the Linux engineers who embedded that assumption into /dev/random. (That has been resolved on the Linux side for some time now.) I will claim (without evidence) to be a subject matter expert on this topic.

Re: Three mistakes from Dart/Flutter's weak PRNG

#63
post #62

Earlier quoted context omitted.

That's absolutely not true, and some of us have directly experienced what happens when it runs out. There are implementations that will keep producing output without an ongoing and sufficient supply of fresh entropy, but there are also implementations that do not. Generally, those that do keep producing output in those cases are formally weaker. When the supply is treated conscientiously, depletion broadly doesn't ma…

No, you are mistaken, as were the Linux engineers who embedded that assumption into /dev/random. (That has been resolved on the Linux side for some time now.) I will claim (without evidence) to be a subject matter expert on this topic.

"It was an issue in Linux for a while, but isn't in recent kernels" is not really sufficient grounds for acting like it's not an issue.

A language designer or library developer, especially, generally can't assert that their code will only run on the most robust, modern, popular systems currently available. They need to work defensively, anticipating the issues that they may plausibly encounter -- especially where those issues will not be apparent to less expert application developers.

And those less expert application developers are in an even worse position, because many barely even know what they're doing in the first place, making all kinds of foolish decisions while they paste together their docker script and relying on inexpert devops/sre people (or end users!) who make their own choices about what things are running on.

It's encouraging to learn that there are now established, widespread, inexhaustibly secure RNG's out there. But it remains irrelevant to a discussion of what developers need to keep themselves mindful of because there remain many implementations in the wild that don't behave like that and most developers aren't in a position to guarantee which their code will encounter.

Re: Three mistakes from Dart/Flutter's weak PRNG

#64

Earlier quoted context omitted.

With any question like this, the path to an answer follows three intermediate questions: 1. Was there a security problem that resulted from the use of this insecure generator? 2. Were the developers who encountered this problem completely unreasonable and in the wrong, or were they simply non-(security)-experts who developed software that happened to have a security vulnerability? 3. If the latter, did the language/t…

I think most very experienced engineers would strongly disagree with you on (2) and would laugh at the usage characterization you make in (4). On #2: The difference between a PRNG and a cryptographically secure random number generator is foundational knowledge for software engineers, and there's (finally) a strong trade consensus that writing security-sensitive code has a higher bar of preparation and shouldn't be do…

I think the following statements are entirely compatible with one another:

* Most software developers (let's say, 95-99%+) are smart enough to avoid using insecure PRGs in their code.

* The remaining 1-5% have contributed to a litany of avoidable security disasters, nonetheless.

* The impact of these disasters has been vastly outsized when you compare it to the number of bad developers.

* If every developer understood that they needed security expertise (and indeed, that they were even writing security critical code, the world would be a very different place than it is.)

As Thomas mentioned below, I am something of a collector and obsessive when it comes to incidents of bad random number generation. What's fascinating to me about this Dart/Flutter story is not the result, it's that I haven't seen one of these stories in a long time!

By this I mean: this type of incident used to pop up on HN every month or so, and yet in the past few years they've become incredibly rare. And do you know why that is? It is not because developers got better. It's almost entirely due to the fact that development frameworks (particularly JS in browsers) have made a multi-year and systematic effort to reduce the availability of insecure default PRGs to bad developers. The result is that an entire bug class has gone from a common, monthly occurrence, to a relative rarity.

The idea that we should use insecure default RNGs because they're good for reproducible testing is a new one on me. If you need reproducible random numbers for your application, but you are asking to use an interface that does not explicitly include the fact that it generates non-random, reproducible numbers then you are doing both software development and testing wrong, IMHO.

Re: Three mistakes from Dart/Flutter's weak PRNG

#65

Earlier quoted context omitted.

I think most very experienced engineers would strongly disagree with you on (2) and would laugh at the usage characterization you make in (4). On #2: The difference between a PRNG and a cryptographically secure random number generator is foundational knowledge for software engineers, and there's (finally) a strong trade consensus that writing security-sensitive code has a higher bar of preparation and shouldn't be do…

I think the following statements are entirely compatible with one another: * Most software developers (let's say, 95-99%+) are smart enough to avoid using insecure PRGs in their code. * The remaining 1-5% have contributed to a litany of avoidable security disasters, nonetheless. * The impact of these disasters has been vastly outsized when you compare it to the number of bad developers. * If every developer understoo…

> this type of incident used to pop up on HN every month or so, and yet in the past few years they've become incredibly rare. And do you know why that is? It is not because developers got better. It's almost entirely due to the fact that development frameworks (particularly JS in browsers) have made a multi-year and systematic effort to reduce the availability of insecure default PRGs to bad developers. The result is that an entire bug class has gone from a common, monthly occurrence, to a relative rarity.

That's a fair take and worth considering.

I suspect this whole dilemma speaks to a widening divide between those who see security as the top and inviolate priority in modern software and those still seeing software as something with much more varied and heterogenous concerns. And that gap gets most contentious when it comes to what things like what should be considered default, what capabilities should be available altogether, how convenient those features should be made, what emphasis should be made in education/training/mentorship, etc.

Undoubtedly, (often sloppy) network-delivered and network-attached software has come to dominate the industry and with it the consequences of security-practice lapses have become be more severe than they once had been. But at the same time, we can watch as things like correctness, stability, resource-efficiency, performance-efficiency, maintenance/repair-ability, etc tumble away and turn much of the same software into byzantine garbage that barely runs on X-core YYY-ghz hardware with ZZ-gigabytes of RAM and faults have the time when it does.

So I think there's a real tension, but I get where you're coming from. It may in fact be true that making a seeded PRNG less easily available would be a wise favor to the security-first-and-always people. :D

Re: Three mistakes from Dart/Flutter's weak PRNG

#66
post #57

Earlier quoted context omitted.

The person you're responding to is pretty familiar with the space you're commenting on, for whatever it's worth to you to know.

Hah! Thanks for bringing that to my attention. :)

I missed it too (sorry, Matt) --- I wrote my comment in bed half awake (I have a problem) and without glasses (I'm old) I can't see for shit.

Re: Three mistakes from Dart/Flutter's weak PRNG

#67
post #62

Earlier quoted context omitted.

No, you are mistaken, as were the Linux engineers who embedded that assumption into /dev/random. (That has been resolved on the Linux side for some time now.) I will claim (without evidence) to be a subject matter expert on this topic.

"It was an issue in Linux for a while, but isn't in recent kernels" is not really sufficient grounds for acting like it's not an issue. A language designer or library developer, especially, generally can't assert that their code will only run on the most robust, modern, popular systems currently available. They need to work defensively, anticipating the issues that they may plausibly encounter -- especially where tho…

No, there's really no space for wriggling here. You use getrandom() or, in the worst case, /dev/urandom, and this kernel nit goes away. It was never the case that the LRNG was "exhaustible"; there was only a broken interface to it.

Re: Three mistakes from Dart/Flutter's weak PRNG

#68
post #55

Earlier quoted context omitted.

No, it's definitely true. A conventional OS CSPRNG can be effectively modeled as a stream cipher, where the key is a hash of observed entropy. As you encrypt more bytes with a stream cipher, you don't "deplete key". Real CSPRNGs are more complex than this, but that complexity is there to improve things from the baseline of "hash some interrupts and key ChaCha20 with it"; the argument gets weaker on real CSPRNGs, not…

> Unfortunately, Linux encoded that meme into its legacy KRNG ("/dev/random"), so lots of people believe it to be real. It is not, and modern userland programs don't use "/dev/random" anyways. It's not the only such system, nor has that "legacy KPRN" been eradicated from real-world use. Moreso, I can't understand how someone who seemingly has as much seasoning and experience as yourself can fathom making generalizing…

"KRNG" => kernel random number generator.

"LRNG" => (idiosyncratic) shorthand for "Linux's KRNG".

The LRNG never had the problem you're alluding to. It's not as if the literature eventually found "inexhaustible" designs. They were never exhaustible. There is no such danger. You can get to this axiomatically by looking at how a CSPRNG works (again: it's effectively a stream cipher construction), or empirically by reading about it. Either way: no, you're wrong here.

Re: Three mistakes from Dart/Flutter's weak PRNG

#69
post #68

Earlier quoted context omitted.

> Unfortunately, Linux encoded that meme into its legacy KRNG ("/dev/random"), so lots of people believe it to be real. It is not, and modern userland programs don't use "/dev/random" anyways. It's not the only such system, nor has that "legacy KPRN" been eradicated from real-world use. Moreso, I can't understand how someone who seemingly has as much seasoning and experience as yourself can fathom making generalizing…

"KRNG" => kernel random number generator. "LRNG" => (idiosyncratic) shorthand for "Linux's KRNG". The LRNG never had the problem you're alluding to. It's not as if the literature eventually found "inexhaustible" designs. They were never exhaustible. There is no such danger. You can get to this axiomatically by looking at how a CSPRNG works (again: it's effectively a stream cipher construction), or empirically by read…

As a project rescue specialist whose had to diagnose and treat exactly this issue more than once, I feel like I'm being gaslit, although I know that's not your intent.

As recently as node 16 or 18 or so, which is still in real-world use despite its age, reaning on the real-word docker images that these projects use, it happens. And when it does, you can rightly guess that all the client's javascript developers were utterly perplexed specifically because they'd never heard of such a concern. But you point to the stack trace for when their call to uuid never resolves and provide all the documentation from familiar bloggers to help them wrap their heads around it, and voila -- the mysterious and catastrophic issue that's been plaguing them is suddenly remedied.

As I said, I appreciate that exhaustion doesn't need to happen in anything with an appropriate design. That's genuinely great. But even if it's just a certain and inappropriate way of using the linux RNG in a certain window of Linux versions (and I'm not strictly convinced its even so narrow a scenario), that's a actually a pretty common real thing that real developers will continue to encounter in the wild for longer than any us might want, and not some baseless myth or meme.

Re: Three mistakes from Dart/Flutter's weak PRNG

#70
post #68

Earlier quoted context omitted.

"KRNG" => kernel random number generator. "LRNG" => (idiosyncratic) shorthand for "Linux's KRNG". The LRNG never had the problem you're alluding to. It's not as if the literature eventually found "inexhaustible" designs. They were never exhaustible. There is no such danger. You can get to this axiomatically by looking at how a CSPRNG works (again: it's effectively a stream cipher construction), or empirically by read…

As a project rescue specialist whose had to diagnose and treat exactly this issue more than once, I feel like I'm being gaslit, although I know that's not your intent. As recently as node 16 or 18 or so, which is still in real-world use despite its age, reaning on the real-word docker images that these projects use, it happens. And when it does, you can rightly guess that all the client's javascript developers were u…

You're not being gaslit by me, but rather by older Linux kernels. There's no such thing as exhaustion. But there's a legacy kernel interface that pretends there is. The implication of using it is that your program will randomly stall, because the kernel is (was) galighting you. But that's not a cryptographic security issue.

Honestly it's kind of refreshing to see a thread like this. This was a live issue on HN like 10 years ago, when cryptographers started yelling at Ted T'so about how dumb "/dev/random" was, and generalist engineers on HN argued about it. But it has since become a settled matter --- here, I mean. Among cryptography engineers: never a doubt.

There are KRNG security issues! You can come up with cases, especially with embedded software or older hypervisors, where code runs with an unseeded RNG. That's very bad. But those issues aren't relevant to ordinary userland code; if your system can't run with the assumption that "/dev/urandom" is seeded, you're fucked for other reasons, so distributions (and hypervisors) go out of their way to ensure that can't happen.

At any rate: there is no case where "exhaustion" comes into play, and there never has been, but there was an archaic kernel interface in Linux that thought there could be such a thing, so there's a whole generation of Linux developers who believe it's a big deal. It is not.

Post reply on HN