8

This question may be a little off-topic, but is Math.random the same as crypto.getRandomValues? (JavaScript)

Here's an example:

Math.random(); // 0.11918419514323941
self.crypto.getRandomValues(new Uint32Array(10))[0]; // 2798055700
(Using "self" for cross-site prevention)

They don't output the same number or nearly the same length, but I'm wondering if "crypto.getRandomValues" is more secure then "Math.random"?

A user told me (on this site) that I should use "crypto.getRandomValues" instead of "Math.random" for JavaScript security. All of this is for a JavaScript security project.

Parking Master
  • 241
  • 1
  • 9
  • 2
    Does this answer your question? [Why is Math.random() not designed to be cryptographically secure?](https://security.stackexchange.com/questions/181580/why-is-math-random-not-designed-to-be-cryptographically-secure) – forest Nov 12 '21 at 22:32
  • @forest I have already found the answer below. – Parking Master Nov 12 '21 at 23:38
  • 1
    OK, fair enough. I've retracted my duplicate vote. – forest Nov 12 '21 at 23:39

2 Answers2

27

See MDN: Crypto.getRandomValues(), where it reads:

The Crypto.getRandomValues() method lets you get cryptographically strong random values.

(emphasis mine)

In contrast, see MDN: Math.random(), where it reads:

Note: Math.random() does not provide cryptographically secure random numbers. Do not use them for anything related to security. Use the Web Crypto API instead, and more precisely the window.crypto.getRandomValues() method.

(emphasis mine)

Laurel
  • 129
  • 7
mti2935
  • 19,868
  • 2
  • 45
  • 64
13

Your friend is correct; always use Crypto.getRandomValues instead of Math.random for anything related to security.

Math.random is designed for statistical simulations; and the numbers it produces are supposed to be randomly scattered around the number space. However, it is not designed to produce "unguessable" numbers, only numbers that are good for statistics. In other words, it doesn't matter in a simulation if your numbers have some internal pattern, or if you can repeat the random sequence.

The Crypto library, on the other hand, is designed to give numbers that are unguessable. They are not just random, but they have no identifiable relationship to each other. Learning a million random numbers output by it still won't reveal an inner pattern that helps you guess the next random value.

John Deters
  • 33,650
  • 3
  • 57
  • 110
  • It's weird that Math.random constantly changes, and has a higher length than Crypto.getRandomValue, but it is still less secure. – Parking Master Nov 12 '21 at 20:18
  • 4
    Creating unguessable numbers is a very hard problem for a computer. Every aspect of a computer is deterministic; they aren't designed to output different values when given the same inputs. It takes special effort to collect truly random event data to seed the Crypto random number generator. – John Deters Nov 12 '21 at 20:21
  • 3
    @ParkingMaster The difference is when you have knowledge about how the RNG works. With any decent RNG, you won't see any pattern in the output. If you did, it would not look random in a statistical sense. The question is: _knowing how the RNG works internally_, can you deduce its internal state by looking at an output sequence? (Or rather: can you do it in reasonable computation time, using a reasonable output sequence length?) – Szabolcs Nov 13 '21 at 10:37
  • 2
    @Szabolcs “knowledge about how the RNG works” is a very misleading way to put it. I can tell you that my RNG is CTR_DRBG with this and that parameter, so you'll know everything about it except for the seed, and you still won't be able to predict its outputs. Conversely, if you're knowledgeable about the topic, you'll probably be able to predict outputs of a non-crypto RNG having seen a few hundreds/thousands/… outputs. The patterns in a non-crypto RNG are there if you know how to look at them. – Gilles 'SO- stop being evil' Nov 13 '21 at 13:55
  • @JohnDeters Modern computers of the PC/smartphone kind are not deterministic devices: their processor has a component which is specifically designed to produce unpredictable random output (a TRNG). An increasing number of embedded devices have a TRNG too. Any device that can do TLS needs to have an RNG (whether seeded by a built-in TRNG or by a trusted third party, e.g. during manufacturing). – Gilles 'SO- stop being evil' Nov 13 '21 at 13:57
  • @Gilles'SO-stopbeingevil' That component **is** the "special effort to collect truly random event data" that John Deters mentioned. The fact that it is built into the hardware is _convenient_, but doesn't change the fact that it requires a discrete piece of hardware, and is not something you can create from parts already found in the computer. (Compare, for instance, graphics processing, which can be entirely achieved with a generic CPU, but is just _more efficient_ on a dedicated GPU.) – IMSoP Nov 13 '21 at 17:22
  • @IMSoP A dedicated TRNG component is not the only way to obtain unpredictable numbers on a computer. (But their existence means that a modern computer is not deterministic.) You can also inject randomness during manufacturing. Or you can do what PC's used to do (still do but it's mostly useless when you have a TRNG), which is collect external environmental data (e.g. interrupt timing) that your adversaries can't predict — the difficulty with that being that it's difficult to know when you have enough for security. – Gilles 'SO- stop being evil' Nov 13 '21 at 18:24
  • 2
    @ParkingMaster The reason that it may seem that Math.random() returns a value that is greater in length than the value returned by Crypto.getRandomValues() is that Math.random() returns a decimal value between 0 and 1, whereas Crypto.getRandomValues() returns a 32 bit unsigned integer (i.e. an integer between 0 and 42949672965). If you do `crypto.getRandomValues(new Uint32Array(1))[0]/4294967296` and compare to `Math.random()`, you'll see that they both return values that are the same in length. – mti2935 Nov 13 '21 at 19:44
  • 1
    @mti2935 actually, that makes sense. Because `Math.random` returns `0.{some number}` between one and zero, and like you said `crypto.getRandomValues(new Uint32Array(10))[0];` returns a 32 bit unsigned integer. – Parking Master Nov 13 '21 at 19:46
  • @Gilles'SO-stopbeingevil' I think I've had this same debate before, if not with you with someone else on this site. It comes down to what you count as "the computer", and what you count as "special effort". I think it's perfectly reasonable to say that the parts of a computer that run normal software (including library functions like Math.random) are purely deterministic, and need external input - whether dedicated hardware or "accidental" sources like event and signal noise - to generate true randomness. But I guess it's also true that "every aspect" is not a good choice of words. – IMSoP Nov 13 '21 at 21:13
  • 1
    @mti2935 I have updated the securityjs.128 file, and used `crypto.getRandomValues(new Uint32Array(10))[0];` instead – Parking Master Nov 13 '21 at 22:10
  • 1
    Parking Meter, That's great news. I'm sure @vidarlo will be happy to see this as well. – mti2935 Nov 13 '21 at 22:28
  • @mti2935 "Parking Meter" lol... – Parking Master Nov 16 '21 at 00:11