diff --git a/src/services/passwordGenerationService.js b/src/services/passwordGenerationService.js index bb74535b..a2d04e30 100644 --- a/src/services/passwordGenerationService.js +++ b/src/services/passwordGenerationService.js @@ -99,8 +99,39 @@ function initPasswordGenerationService() { return password; }; + // EFForg/OpenWireless + // ref https://github.com/EFForg/OpenWireless/blob/master/app/js/diceware.js function randomInt(min, max) { - return Math.floor(Math.random() * (max - min + 1)) + min; + var rval = 0; + var range = max - min; + + var bits_needed = Math.ceil(Math.log2(range)); + if (bits_needed > 53) { + throw new Exception("We cannot generate numbers larger than 53 bits."); + } + var bytes_needed = Math.ceil(bits_needed / 8); + var mask = Math.pow(2, bits_needed) - 1; + // 7776 -> (2^13 = 8192) -1 == 8191 or 0x00001111 11111111 + + // Create byte array and fill with N random numbers + var byteArray = new Uint8Array(bytes_needed); + window.crypto.getRandomValues(byteArray); + + var p = (bytes_needed - 1) * 8; + for (var i = 0; i < bytes_needed; i++) { + rval += byteArray[i] * Math.pow(2, p); + p -= 8; + } + + // Use & to apply the mask and reduce the number of recursive lookups + rval = rval & mask; + + if (rval >= range) { + // Integer out of acceptable range + return randomInt(min, max); + } + // Return an integer that falls within the range + return min + rval; } function extend() {