Let's start with a warning; just in case
Honestly, I'm not sure why you would want to use something beyond window.crypto.getRandomValues
(or its Linux equivalent /dev/random
). If you're planning to "stretch" its output for some reason, chances are you're doing it wrong. Whatever your scenario is, don't hardcode such a seed seed into your script before serving it to clients. Not even if your .js
file is created dynamically on the server side. That would be as if you would push encrypted data together with your encryption key… voiding any security gains in its root.
That being said, let's look at your question in your line of thinking…
About your idea
The output of math.random
is insecure as it produces predictable outputs. Meaning: having a sequence of outputs, an attacker can successfully recover the state and the following outputs it will produce. Seeding it with a cryptographically secure seed from window.crypto.getRandomValues
(or its Linux equivalent /dev/random
) will not fix that problem.
As a securer approach you might want to take a look at ChaCha20, which is a cryptographically secure stream cipher. It definitely produces securer outputs than math.random
and I've seen several pure vanilla implementation of ChaCha20 at Github et al. So, using something "safer" than math.random
shouldn't be all too hard to implement in your script(s). Seed ChaCha20 with window.crypto.getRandomValues
(or its Linux equivalent /dev/random
) as you were planning to do and you're set.
But…
Please note that I haven't dived into the use of Javascript for crypto purposes itself. Doing so tends to introduce attack vectors. Which is why you'ld (at least) need HTTPS when your project is served online. I'll have to skip mentioning all the other related nitpicks… mainly because you didn't mention such details in your question, but also to prevent this answer from getting too broad/long. A quick search at Security.SE tends to enlighten you about using-Javascript-for-crypto related issues.
Instead - use the Web Cryptographic API
Last but not least, I'ld like to get back to what I said for starters and point you to the fact that you might as well simply use window.crypto.getRandomValues
(or its Linux equivalent /dev/random
) for all randomness purposes. The speed gains of not doing so are minimal in most scenarios.
Crypto is hard… don't break your neck trying to solve problems on your own. Even for Javascript, an applicable solution already exist:
Web Cryptographic API - Example:
/* assuming that window.crypto.getRandomValues is available */
var array = new Uint32Array(10);
window.crypto.getRandomValues(array);
console.log("Your lucky numbers:");
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
See, most modern browsers support a minimum of CryptoAPI which allows your clients to call obj.getRandomValues()
from within Javascript - which is practically a call to the system's getRandomValues
or /dev/random
.
Some final words regarding polyfills
If you really must support outdated browsers, decent polyfills can close the gap. But when it comes to security, both "using old browsers" as well as "using polyfills" is a nightmare waiting to go wrong. Instead, be professional and educate clients about the fact that its easier to upgrade to a newer browser, than to pick up polyfills and the problems that come with them.
Murphy's Law applies here: When using polyfills for security/cryptography, what can go wrong will go wrong!
In the end, its always better to be safe and not use polyfills just to support some outdated browsers, than to be sorry when stuff hits the fan. A browser update will cost your client a few minutes. A cryptographic polyfill that fails ruins your reputation forever. Remember that!