Slumpgenerator

Så fungerar crypto.getRandomValues()

crypto.getRandomValues() är en metod från Web Crypto API som genererar kryptografiskt säkra slumptal. Till skillnad från Math.random() hämtar den värden från entropikällor i operativsystemet, vilket gör den lämplig för säkerhetskänsliga applikationer och vardagliga generatorer.

Äkta slumpmässighet är svårare att uppnå än man tror
Äkta slumpmässighet är svårare att uppnå än man tror
Innehållsförteckning

Vad är crypto.getRandomValues() och hur fungerar det?

crypto.getRandomValues() är en del av Web Crypto API, som är inbyggt i moderna webbläsare och Node.js. Till skillnad från Math.random(), som använder en deterministisk pseudoslumptalsgenerator (PRNG), fyller crypto.getRandomValues() en typarray med kryptografiskt starka slumpmässiga värden hämtade från operativsystemets entropipool.

På de flesta operativsystem samlas denna entropi in från källor som hårdvaruavbrott, musrörelser, tangentbordstiming och liknande oförutsägbara händelser. Eftersom värdena hämtas från fysisk slumpmässighet snarare än en fast algoritm är de mycket svårare att förutsäga eller reproducera.

Metoden tar emot en typarray – till exempel Uint8Array, Uint16Array eller Uint32Array – och fyller den med slumpmässiga värden:

const array = new Uint32Array(1)

crypto.getRandomValues(array)
console.log(array[0]) // Ett kryptografiskt slumpmässigt 32-bitarsheltal

Varför crypto.getRandomValues() är starkare än Math.random()

Den viktigaste skillnaden handlar om förutsägbarhet:

  • Math.random() använder en seedbaserad algoritm. I teorin går det att förutsäga sekvensen om man känner till startvärdet eller tillräckligt många utdata. Webbläsare exponerar inte startvärdet, men den underliggande PRNG:en är inte utformad med säkerhet i åtanke.

  • crypto.getRandomValues() hämtar värden från systemets entropipool, som kontinuerligt fylls på med data från hårdvaruhändelser. Att förutsäga dess utdata utan tillgång till hårdvaran är beräkningsmässigt omöjligt.

För tillämpningar som att generera tokens, identifierare eller annat där förutsägbarhet måste undvikas är crypto.getRandomValues() rätt val. För spel, animationer eller visuell variation där säkerhet inte är ett krav är Math.random() fortfarande ett fullt giltigt alternativ.

Läs mer om hur Math.random() fungerar och varför vi till slut gick vidare från det.

Hur Slumpgenerator använder crypto.getRandomValues()

Slumpgenerator byggdes ursprungligen med Math.random() för att driva sina generatorer. Även om detta fungerar bra för de flesta ändamål är det inte kryptografiskt säkert – värdena kan i teorin förutsägas om man känner till det interna tillståndet i PRNG:en.

Vi har sedan dess migrerat all slumptalsgenerering till att använda crypto.getRandomValues(). Det ger alla generatorer – från nummergeneratorn till tärningskastaren – en starkare grund för slumpmässighet.

Internt använder alla generatorer en gemensam hjälpfunktion kallad cryptoRandom(), som omsluter crypto.getRandomValues() och returnerar ett flyttal i intervallet [0, 1) – samma gränssnitt som Math.random(). Detta gör den enkel att använda som en direkt ersättning:

const cryptoRandom = () => {
  if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
    const array = new Uint32Array(1)

    crypto.getRandomValues(array)

    return array[0] / 2 ** 32
  }

  return Math.random()
}

Genom att dividera det slumpmässiga 32-bitarsheltal med 2^32 (4 294 967 296) får vi ett tal i intervallet [0, 1), precis som Math.random(). Återfallet till Math.random() finns med för miljöer där Web Crypto API inte är tillgängligt, men detta är extremt sällsynt i moderna webbläsare.

Denna cryptoRandom()-funktion används sedan för att bygga hjälpverktyg på högre nivå:

// Välj ett slumpmässigt element ur en array
const random = (array) => array[Math.floor(cryptoRandom() * array.length)]

// Generera ett slumpmässigt heltal i ett intervall
const randomInRange = (min, max) =>
  Math.floor(cryptoRandom() * (max - min + 1)) + min

Webbläsarstöd och tillgänglighet

crypto.getRandomValues() stöds i alla moderna webbläsare och har funnits tillgänglig i många år. Det finns också tillgängligt i Node.js (version 15+) som globalThis.crypto.getRandomValues().

Läs mer om metoden på Mozillas hemsida MDN.

Översättningar

Senast uppdaterad av Vincent Lejtzén.