Beveilig willekeurige getallen in javascript?

Hoe genereer ik cryptografisch veilige willekeurige getallen in javascript?


Antwoord 1, autoriteit 100%

Er is discussie geweest op WHATWG over het toevoegen van dit aan het window.crypto-object. Je kunt de discussielezen en de voorgestelde APIen webkit-bug (22049).

Zojuist de volgende code in Chromeom een ​​willekeurige byte te krijgen:

(function(){
  var buf = new Uint8Array(1);
  window.crypto.getRandomValues(buf);
  alert(buf[0]);
})();

Snippet uitvouwen


Antwoord 2, autoriteit 45%

In volgorde, denk ik dat uw beste weddenschappen zijn:

  1. window.crypto.getRandomValues ​​of window.msCrypto.getRandomValues
  2. De randomWords-functie van de sjcl-bibliotheek (http://crypto.stanford.edu/sjcl/)
  3. De random number generator van de isaac-bibliotheek (die is gezaaid door Math.random, dus niet echt cryptografisch veilig) (https://github.com/rubycon/isaac.js)

window.crypto.getRandomValues ​​is al een tijdje in Chrome geïmplementeerd en relatief recent ook in Firefox. Helaas implementeren Internet Explorer 10 en eerder de functie niet. IE 11 heeft window.msCrypto, waarmee hetzelfde wordt bereikt. sjcl heeft een geweldige generator voor willekeurige getallen die wordt gegenereerd op basis van muisbewegingen, maar er is altijd een kans dat de muis niet voldoende is verplaatst om de generator te seeden, of dat de gebruiker op een mobiel apparaat zit waar geen enkele muisbeweging is. Daarom raad ik aan om een ​​fallback-case te hebben waarin je nog steeds een niet-beveiligd willekeurig nummer kunt krijgen als er geen keuze is. Dit is hoe ik dit heb aangepakt:

function GetRandomWords (wordCount) {
    var randomWords;
    // First we're going to try to use a built-in CSPRNG
    if (window.crypto && window.crypto.getRandomValues) {
        randomWords = new Int32Array(wordCount);
        window.crypto.getRandomValues(randomWords);
    }
    // Because of course IE calls it msCrypto instead of being standard
    else if (window.msCrypto && window.msCrypto.getRandomValues) {
        randomWords = new Int32Array(wordCount);
        window.msCrypto.getRandomValues(randomWords);
    }
    // So, no built-in functionality - bummer. If the user has wiggled the mouse enough,
    // sjcl might help us out here
    else if (sjcl.random.isReady()) {
        randomWords = sjcl.random.randomWords(wordCount);
    }
    // Last resort - we'll use isaac.js to get a random number. It's seeded from Math.random(),
    // so this isn't ideal, but it'll still greatly increase the space of guesses a hacker would
    // have to make to crack the password.
    else {
        randomWords = [];
        for (var i = 0; i < wordCount; i++) {
            randomWords.push(isaac.rand());
        }
    }
    return randomWords;
};

Je moet sjcl.js en isaac.js opnemen voor die implementatie, en zorg ervoor dat je de sjcl entropy collector start zodra je pagina is geladen:

sjcl.random.startCollectors();

sjcl is BSD en GPL met dubbele licentie, terwijl isaac.js MIT is, dus het is volkomen veilig om een ​​van beide in elk project te gebruiken. Zoals vermeld in een ander antwoord, is clipperz een andere optie, maar om welke bizarre reden dan ook, het is gelicentieerd onder de AGPL. Ik heb nog niemand gezien die lijkt te begrijpen welke implicaties dat heeft voor een JavaScript-bibliotheek, maar ik zou het over het algemeen vermijden.

Een manier om de code die ik heb gepost te verbeteren, is door de status van de isaac-generator voor willekeurige getallen op te slaan in localStorage, zodat deze niet elke keer dat de pagina wordt geladen opnieuw wordt geplaatst. Isaac zal een willekeurige reeks genereren, maar voor cryptografiedoeleinden is het zaadje van het grootste belang. Seeding met Math.random is slecht, maar in ieder geval een beetje minder slecht als het niet noodzakelijkerwijs bij elke pagina wordt geladen.


Antwoord 3, autoriteit 39%

Je kunt bijvoorbeeld muisbewegingen gebruiken als zaad voor willekeurige getallen, de tijd en muispositie uitlezen wanneer de onmousemove-gebeurtenis plaatsvindt, die gegevens naar een whitening-functie sturen en je hebt een eersteklas willekeurig exemplaar bij de hand. Zorg er echter voor dat de gebruiker de muis voldoende heeft bewogen voordat u de gegevens gebruikt.

Bewerken: ik heb zelf een beetje met het concept gespeeld door een wachtwoordgenerator te maken. Ik kan niet garanderen dat mijn whitening-functie foutloos is, maar omdat ik constant opnieuw wordt geplaatst, ben ik er vrij zeker van dat het genoeg is voor de baan: e-business. hopto.org/generator.htm

Bewerken2: het werkt nu een beetje met smartphones, maar alleen door de aanraakfunctionaliteit uit te schakelen terwijl de entropie wordt verzameld. Android werkt op geen enkele andere manier goed.


Antwoord 4, autoriteit 10%

om een ​​cryptografisch sterk getal uit het bereik [0, 1)(vergelijkbaar met Math.random()) te krijgen, gebruikt u crypto:

let random = ()=> crypto.getRandomValues(new Uint32Array(1))[0]/2**32;
console.log( random() );

Snippet uitvouwen


Antwoord 5, autoriteit 6%

Misschien wil je het proberen
http://sourceforge.net/projects/clipperzlib/
Het heeft een implementatie van Fortuna, een cryptografisch veilige generator voor willekeurige getallen. (Kijk eens naar src/js/Clipperz/Crypto/PRNG.js). Het lijkt de muis ook als een bron van willekeur te gebruiken.


Antwoord 6, autoriteit 2%

Allereerst heb je een bron van entropie nodig. Bijvoorbeeld beweging van de muis, wachtwoord of iets anders. Maar al deze bronnen zijn verre van willekeurig en garanderen u 20 bits entropie, zelden meer. De volgende stap die u moet nemen, is om het mechanisme te gebruiken zoals “Password-Based KDF”, het maakt het rekenkundig moeilijk om gegevens van willekeurig te onderscheiden.


Antwoord 7

Vele jaren geleden moest u uw eigen generator voor willekeurige getallen implementeren en deze voorzien van entropie die werd verzameld door muisbewegingen en timinginformatie. Dit was het Phlogiston-tijdperk van JavaScript-cryptografie. Tegenwoordig hebben we window.cryptoom mee te werken.

Als je een willekeurig integernodig hebt, willekeurig getal -csprngis een goede keuze. Het genereert veilig een reeks willekeurige bytes en converteert deze vervolgens naar een onbevooroordeeld willekeurig geheel getal.

const randomInt = require("random-number-csprng");
(async function() {
    let random = randomInt(10, 30);
    console.log(`Your random number: ${random}`);
})();

Als je een willekeurig getal met drijvende komma nodig hebt, moet je wat meer werk doen. Over het algemeen is veilige willekeur echter een geheel getal, geen probleem met drijvende komma.

Other episodes