In what situations is it acceptable (from a security standpoint) to use node's crypto.pseudoRandomBytes
instead of the cryptographically-strong crypto.randomBytes
?
I assume pseudoRandomBytes
performs better at the expense of being more predictable (incorrect), but the docs don't really have much to say about how less-strong it is.
Specifically, I'm wondering if I'm ok using pseudoRandomBytes
to generate a CSRF token.
As it turns out, with the default OpenSSL (which is bundled with node, but if you've built your own, it is possible to configure different engines), the algorithm to generate random data is exactly the same for both randomBytes
(RAND_bytes
) and pseudoRandomBytes
(RAND_pseudo_bytes
).
The one and only difference between the two calls depends on the version of node you're using:
- In node v0.12 and prior,
randomBytes
returns an error if the entropy pool has not yet been seeded with enough data. pseudoRandomBytes
will always return bytes, even if the entropy pool has not been properly seeded.
- In node v4 and later,
randomBytes
does not return until the entropy pool has enough data. This should take only a few milliseconds (unless the system has just booted).
Once the the entropy pool has been seeded with enough data, it will never "run out," so there is absolutely no effective difference between randomBytes
and pseudoRandomBytes
once the entropy pool is full.
Because the exact same algorithm is used to generate randrom data, there is no difference in performance between the two calls (one-time entropy pool seeding notwithstanding).
Just a clarification, both have the same performance:
var crypto = require ("crypto")
var speedy = require ("speedy");
speedy.run ({
randomBytes: function (cb){
crypto.randomBytes (256, cb);
},
pseudoRandomBytes: function (cb){
crypto.pseudoRandomBytes (256, cb);
}
});
/*
File: t.js
Node v0.10.25
V8 v3.14.5.9
Speedy v0.1.1
Tests: 2
Timeout: 1000ms (1s 0ms)
Samples: 3
Total time per test: ~3000ms (3s 0ms)
Total time: ~6000ms (6s 0ms)
Higher is better (ops/sec)
randomBytes
58,836 ± 0.4%
pseudoRandomBytes
58,533 ± 0.8%
Elapsed time: 6318ms (6s 318ms)
*/
If it's anything like the standard PRNG implementations in other languages, it is probably either not seeded by default or it is seeded by a simple value, like a timestamp. Regardless, the seed is possibly very easily guessable.