News for hackers. Stuff that matters.
Re:There's Math.random(), and then there's Math.random() by maxloh on Friday February 07, 2025 @02:54AM (#42970456)
I learned in college that most random number generators use the current timestamp to generate a pseudo-random number.

How does this differ cryptographically from algorithms like MWC1616 and xorshift128+ in backend applications? How can a random number generator be vulnerable to attacks in real life?

Does it really matter which random number generator you use on a webpage? It's already considered an insecure environment anyway (that's why we have server-side validation).

Re:There's Math.random(), and then there's Math.random() by masklinn on Friday February 07, 2025 @03:11AM (#42970520)
> I learned in college that most random number generators use the current timestamp to generate a pseudo-random number.

> How does this differ cryptographically from algorithms like MWC1616 and xorshift128+ in backend applications?

That question doesn’t make any sense. The current timestamp would be a seed to initialise the PRNG, which can be MWC or xorshift.

> Does it really matter which random number generator you use on a webpage?

That is application dependent. If you’re coding a roulette wheel no, if you’re coding an E2E chat yes.

> It's already considered an insecure environment anyway (that's why we have server-side validation).

That is also application dependent. The client is considered insecure from the server pov because it is entirely under user control, so the user can mess with anything. But if it is acting entirely on behalf of the user then that can be the point and by design.

In the example above, you don’t care that a user fucks up their own crypto, but you do care that the crypto holds for the average user.

Even the qualitative difference between two non-CS PRNG can make or break a project due to too small a state space or short a cycle.

Re:There's Math.random(), and then there's Math.random() by sverhagen on Friday February 07, 2025 @05:55AM (#42971292)
I don't really disagree with anything you said, but I think the roulette wheel and the E2E chat are funny examples, you could have a high value roulette game and a casual chat about the weather, where the stakes are opposite to your point ;-)
Re:There's Math.random(), and then there's Math.random() by cratermoon on Friday February 07, 2025 @10:38AM (#42973871)
I was thinking this myself. When significant amounts of real money are sitting on the spin of the wheel and bouncing of the ball, a bad PRNG like the one discussed in the article would be disastrous.
Re:There's Math.random(), and then there's Math.random() by masklinn on Friday February 07, 2025 @10:48AM (#42974011)
Yeah I was thinking less casino thingie and more https://pickerwheel.com, I guess I used the wrong term for it.
Re:There's Math.random(), and then there's Math.random() by tetha on Saturday February 08, 2025 @06:18AM (#42982187)
> That is application dependent. If you’re coding a roulette wheel no, if you’re coding an E2E chat yes.

Or a prominent example are games.

The whole idea of sharing "cool minecraft worlds" or "seeds for cool runs in Balatro/Slay the Spire/..." are possible due to careful use of PRNGs in those games for world generation.

In fact, games often run at least 2 RNGs and possibly more in a multiplayer setting involving networking and encryption of that. You want some kind of "World Generation seed", which is usually a PRNG players can enter funny seeds like "CAFEBABE" into to share worlds. However, you want to protect this PRNG, because otherwise player action changes the world generation.

So you end up with more RNGs of some kind, for example for AI actions, particle movements. And depending on how these RNGs are used, you might link different subsystems together, allowing AI manipulation and such. It's a very interesting thing to think about and design.

Re:There's Math.random(), and then there's Math.random() by tomsmeding on Friday February 07, 2025 @03:03AM (#42970490)
In a class we had to reverse-engineer an application that had encrypted some text file — we had to decrypt it without the key. Turned out the application just used the current unix timestamp as the key. A brute-force search of the past few months didn't take very long.

If you include nanoseconds in your key then you have more entropy, of course, but timestamps are guessable, so it's risky.

Re:There's Math.random(), and then there's Math.random() by sverhagen on Friday February 07, 2025 @05:57AM (#42971300)
Those nanoseconds aren't really entropy then, are they?
Re:There's Math.random(), and then there's Math.random() by lmm on Friday February 07, 2025 @06:35AM (#42971499)
They're entropy for most practical purposes. But there's only 1000 possibilities, so that's less than 10 bits' worth.
Re:There's Math.random(), and then there's Math.random() by boothby on Friday February 07, 2025 @09:05AM (#42972636)
Especially if you're writing a file, the creation time is a big hint! Even nanoseconds won't help if you're leaking that many bits from your seed.
Re:There's Math.random(), and then there's Math.random() by tomsmeding on Friday February 07, 2025 @10:01AM (#42973367)
That's milliseconds; nanoseconds are 1e-9 seconds. Still, the file creation time remark of sibling is pertinent.
Re:There's Math.random(), and then there's Math.random() by lmm on Friday February 07, 2025 @08:04PM (#42979321)
I was thinking of the step from milli to nano, so yeah 1e6 not 1e3, 20 bits not 10. But the point stands.
Re:There's Math.random(), and then there's Math.random() by hapidjus on Friday February 07, 2025 @03:06AM (#42970498)
One attack might be exploiting One Time Passwords. Lets say you send yourself enough tokens to calculate the state, you will then be able to calculate the next token and login as another user. However that should be easily fixed by adding some salt relating to the user, meaning you would only be able to figure out _your_ next token.
Re:There's Math.random(), and then there's Math.random() by atoav on Friday February 07, 2025 @03:09AM (#42970512)
You can go back into a time before computers and use the most famous examples of how bad RNGs endanger crypto: One Time Pads (OTP). This is basically just a XOR of your message with your random numbers. If your random numbers are bad they leave patterns in the XOR-ed message that can be statistically analyzed and potentially decrypted.

Bad PRNGs repeat early and have predictable patterns, as such they form a special attack vector.

Whether that is really an issue for any given application, depends on the application (e.g. how shortlived the crypto is and how bad decryption acter the fact is). But if you are asking that question it likely means you don't know enough knowledge to roll your own crypto unless you wanna be in a world of pain.

Just because PRNGs appear unpredictable to you does not mean they aren't.

If you really wanna go the route, at least add a salt, so something like

  Hash(application_secret_long_and_random + timestamp_nanosecond_precision)
Re:There's Math.random(), and then there's Math.random() by rkangel on Friday February 07, 2025 @05:22AM (#42971148)
They're call PRNG because they are pseudo random. If you know the starting state, you know what sequence they're going to generate. Putting it another way, if you always start them in the same state, they'll always produce the same sequence.

So a PRNG needs "seeding". You need some value to put in at the start that is different every time. Using the time on the computer results in a different seed on each run, and so a different number sequence each time.

If you need random numbers for cryptography (very good quality random numbers are important for lots of crypto processes) then you need to do more - they need to be completely unpredictable. If you just used the time, someone could seed a copy of the RNG with the same time, and predict the randomness sequence. So what we want is a seed that comes from actual randomness (also called "entropy"). That entropy has to come from somewhere - ideally some hardware source using some statistically random physical effect.

Re:There's Math.random(), and then there's Math.random() by magicalhippo on Friday February 07, 2025 @06:07AM (#42971350)
> Putting it another way, if you always start them in the same state, they'll always produce the same sequence.

This can be easy to bump into in fairly trivial cases.

For example, initializing by time alone can be problematic if you spawn N threads at once which all do their own seeding. Then they can all reach the seeding process at the same time, relative to the clock used for the seeding.

I had that problem with one of my earlier ray tracers, and so had to add add the thread id into the mix to seed the PRNGs.

Re:There's Math.random(), and then there's Math.random() by markh1967 on Friday February 07, 2025 @06:37AM (#42971508)
A demonstration of exactly this problem (only in older versions of .Net, newer versions use a different seeding method)

https://dotnetfiddle.net/tLGMp6

Re:There's Math.random(), and then there's Math.random() by mturmon on Friday February 07, 2025 @01:53PM (#42976113)
Agreed. I do a lot of Monte Carlo simulations of physical systems (radars, scientific models) in which same or close seeds will cause trouble.

You do want a deterministic PRNG (for repeatability of the simulation). But if you seed with time alone, and spawn 100 parallel jobs, you will see repeats or near-repeats which will bias the Monte Carlo averages resulting from your simulation ensemble.

In ancient times, you could xor in the PID and the IP address of the host to ensure no seed overlap. Nowadays there are other ways to introduce entropy to the seed, e.g. with dedicated system calls or /dev/random.

Re:There's Math.random(), and then there's Math.random() by simonmales on Friday February 07, 2025 @05:45AM (#42971256)
Well written, h/t.
Re:There's Math.random(), and then there's Math.random() by UncleMeat on Friday February 07, 2025 @08:57AM (#42972544)
The key thing with crypto is not the source of the seed, but the algorithm. Throwing true randomness into a random number generator that isn't mean to provide cryptographic hardness won't save you and a cryptographically secure pseudo random number generator is often just fine when seeded without true randomness.
Re:There's Math.random(), and then there's Math.random() by toast0 on Friday February 07, 2025 @10:10AM (#42973497)
It's both. Cryptographic generators do have better properties on their outputs than noncryptographic hashes (usually at a cost in cpu time, although the cost is often small enough to ignore); but if the seed is guessable, the output sequence is guessable too.

Using timestamp in seconds and process id for example would be easy enough to guess. There was some good work about a decade ago to provide more usable apis to get a quality seed from the OS (getentropy, getrandom), so using a self built seed is pretty suboptimal unless you have a case where you need to repeat the sequence later (recording the seed from the OS is also an option)

Re:There's Math.random(), and then there's Math.random() by UncleMeat on Friday February 07, 2025 @11:29AM (#42974535)
It depends on what you mean by guessable. Guessing a few bits of the seed with confidence won't help you crack a csprng. Yes, people shouldn't be using a timestamp in seconds as a seed. But you also don't need to spring for hardware randomness in order to get strong protections.
Re:There's Math.random(), and then there's Math.random() by kbolino on Friday February 07, 2025 @01:18PM (#42975732)
The problem with using the current time is that "guessing a few bits with confidence" is the same as guessing the whole thing because there's only a few bits that need to be guessed. You might think a time_t value has 55 and growing years worth of values to guess, but in reality, if I'm attacking you or something related to you, I have probably narrowed it down to days, hours, or even just minutes worth of values to guess. Higher-precision timers confer some additional entropy but even then it's usually not enough -- if I'm intercepting live traffic I have a very good idea of the current time, if I'm forging a signature from a certificate I know when it was issued, if I'm trying to decrypt emails or files I usually have attached metadata to narrow my guesses, etc.

The CSPRNG has only made it practically impossible to predict future outputs from past outputs alone; however, if I can guess the seed, I can predict every output past, present, and future. CSPRNGs aren't magic and have to be used properly, and in any security-sensitive context, properly means with a truly random seed. The best CSPRNG in the world cannot create entropy out of thin air. It can, however, stretch a good source of entropy very far. There are cases when using a CSPRNG with a low-quality seed is appropriate, but the minimum acceptable entropy in the seed depends on the application, not on the RNG.

Re:There's Math.random(), and then there's Math.random() by UncleMeat on Friday February 07, 2025 @01:57PM (#42976161)
I'm not saying to use the current time in seconds. I'm saying that the need for "actual randomness" and being "completely unpredictable" in the comment I responded to is largely overblown. Seeds that aren't drawn from true randomness can be totally fine. Seeds that have a handful of highly biased bits can be fine.

There are some cases in crypto where a secret that has even a single bit biased more than epsilon will break a whole scheme. CSPRNGs don't tend to work that way.

Re:There's Math.random(), and then there's Math.random() by kbolino on Friday February 07, 2025 @02:24PM (#42976449)
Ok, yes, there were some algorithms in the past which had problems with carrying input biases to their output and sometimes even getting totally broken with certain seeds/keys. Nowadays, this isn't the case, and the view is that such issues are fundamental weaknesses rather than mere errata to be worked around.

However, the quality of a modern CSPRNG doesn't save you from a low-entropy seed. A couple biased bits in a 128-bit seed may not be a serious issue (but why take the chance?!), however good entropy estimation is a difficult task which is best left to the operating system. Modern operating systems will ingest sources of hardware randomness and seed their system-level CSPRNGs, which should then be used directly by application software (for key material) or as seeds to local CSPRNGs (for less security-sensitive but more performance-sensitive needs). Do not play around with seed entropy just to be clever.

In the absence of a full-fledged operating system, then things like high-precision boot timers can be used for seeds, but only because there's nothing better available. The lack of good randomness is a real problem in resource-constrained environments, though usually there are easier-to-exploit vulnerabilities that get hit first.

Re:There's Math.random(), and then there's Math.random() by spacechild1 on Friday February 07, 2025 @05:24AM (#42971156)
> I learned in college that most random number generators use the current timestamp to generate a pseudo-random number.

People typically seed a PRNG with the current time. The actual output sequence is still created with a determinstic algorithm. These two things are really orthogonal.

Re:There's Math.random(), and then there's Math.random() by Retr0id on Friday February 07, 2025 @05:26AM (#42971171)
xorshift128+ has exactly 128 bits of internal state. After collecting a small number of outputs, it is trivial to determine the internal state by constructing and then solving an equation (where the variables are GF(2) elements), regardless of how the "seed" was initialized. Once you have the internal state, you can predict all future outputs with 100% certainty.

This only becomes a problem when people assume this isn't possible (for example, using it to pick lottery numbers) - this is more likely to happen on the server-side than the client-side (and v8 runs on both), but it can be security-relevant in client-only apps too (consider an insecure "password generator" app).

https://en.wikipedia.org/wiki/GF(2)

Re:There's Math.random(), and then there's Math.random() by Retr0id on Friday February 07, 2025 @06:22AM (#42971426)
By the way, the "password generator app" is not a contrived hypothetical, it was actually one of my first ever bug-bounty payouts.
Re:There's Math.random(), and then there's Math.random() by markh1967 on Friday February 07, 2025 @06:29AM (#42971468)
It's been a while so I can't provide a link but I remember reading about someone who got hold of a video blackjack machine that used a pseudo random number generator and was able to find the seed from only a few hands and then knew exactly which cards would be dealt next. He then went on to empty every machine he could find in the local casinos.
Re:There's Math.random(), and then there's Math.random() by lmm on Friday February 07, 2025 @06:37AM (#42971506)
> I learned in college that most random number generators use the current timestamp to generate a pseudo-random number.

> How does this differ cryptographically from algorithms like MWC1616 and xorshift128+ in backend applications? How can a random number generator be vulnerable to attacks in real life?

In the early days of online poker some people made a killing by figuring out all the possible hands from the PRNGs being used and then they could just start a game and look up the hands they'd been dealt in their database.

Re:There's Math.random(), and then there's Math.random() by jsheard on Friday February 07, 2025 @06:45AM (#42971551)
> I learned in college that most random number generators use the current timestamp to generate a pseudo-random number.

Most modern platforms provide an easy way to get cryptographically strong random numbers, so when seeding a non-cryptographic generator nowadays you may as well seed it with strong randomness rather than using a kludge like the current time.