Also, outside the scope of Cordova apps, Node.js uses OpenSSL rather than /dev/urandom for their crypto.getRandomBytes() implementation, so I don't really trust it in that context. ;)
When you're working with cryptography, you want a uniform distribution of possible values as well as unpredictable randomness.
If you're starting with a random byte and charset.length is an even power of 2, you end up with no bias.
It's better to design functions like this to discard values outside of an acceptable range and try again until they generate a safe value (also, apply a & bit mask to reduce the number of retries). This allows you to accept any arbitrary charset size without being concerned about security.
See also:
https://github.com/paragonie/random_compat/blob/5aa6689651a5...
I'll open a PR tonight if nobody beats me to it.
max = 100
length = 85
num = rand(max)
puts (num * length)/max
Here's an example from Wikipedia (https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#M...)
"For example, assume that your random number source gives numbers from 0 to 99 (as was the case for Fisher and Yates' original tables), and that you wish to obtain an unbiased random number from 0 to 15. If you simply divide the numbers by 16 and take the remainder, you'll find that the numbers 0–3 occur about 17% more often than others. This is because 16 does not evenly divide 100: the largest multiple of 16 less than or equal to 100 is 6×16 = 96, and it is the numbers in the incomplete range 96–99 that cause the bias. The simplest way to fix the problem is to discard those numbers before taking the remainder and to keep trying again until a number in the suitable range comes up. While in principle this could, in the worst case, take forever, the expected number of retries will always be less than one."
From http://stackoverflow.com/questions/16829183/what-is-pseudo-r...