A legtöbb titkosítási rendszer csak akkor biztonságos, ha véletlenszerűen generált jelszavakkal, bitsorozatokkal titkosítunk. Ehhez viszont venni kell valahonnan a véletlen bitek sorozatát.
A véletlenszám-generátor (RNG) egy olyan berendezés vagy szoftver, ami olyan számok sorozatát képes generálni, amiben nincsen semmilyen minta.
Egyszerű berendezésnek tűnhet az elvi leírása alapján, azonban a gond ott kezdődik, hogy igen nehéz algoritmikusan, a kritériumnak megfelelő számsorozatot generálni. Ha esetlegesen valami minta kerül a generátor által előállított számokba, akkor a mintát felhasználva kikövetkeztethető a generátor következő állapota, vagyis onnantól kezdve nem is véletlenszerű a számsorozat.
“Bárki, aki aritmetikai módszerekkel akar előállítani egy véletlen számot, a bűn állapotában leledzik.”
Neumann János
Véletlenszám-generátorokból igen sokfajta létezik. Az olyan véletlenszám-generátorokat (a későbbiekben RNG), amelyek titkosítási és kriptográfiai célokra is alkalmasak, kriptográfiailag biztonságos pszeudó véletlenszám-generátornak nevezi a szakirodalom. Ezt angol mozaikszóval CSPRNG-nek szokás rövidíteni. Egy RNG attól lesz kriptográfiailag biztonságos, hogy átmegy a “következő bit teszten” és kiállja az “állapot kompromittálódási tesztet”.
Egy bitsorozat akkor megy át a következő bit teszten, ha a támadó a bitsorozat bármely i-edik bit előtti sorozatot ismerve matematikai számításokkal levezetve belátható időn belül nem képes megmondani i+1 bit értékét.
Az állapot kompromittálódási teszt igen egyszerű. Ha a támadónak sikerült kitalálnia a generátor jelenlegi állapotát, és ennek ismeretében sikerül kitalálnia a következő állapotot, akkor az algoritmus megbukott az állapot kompromittálódási teszten.
A jobb érthetőség kedvéért nézzünk egy példát. Tételezzük fel, hogy a generátorunk a Pi számjegyeit számító algoritmus, aminek egy inicializációs érték alapján megadjuk, hogy melyik tizedesjegytől kezdje kifejteni a számjegyeket. Normál használat esetén az algoritmusomat mondjuk idő alapján inicializálom egy számjegyre.
Ha a támadónak sikerül kitalálnia az inicializációs értéket, akkor ugyanazt az algoritmust futtatva ugyanazzal a kezdőértékkel ugyanazokat a számjegyeket fogja kapni mint én, ezáltal megbukott a generátorom.
A példában említett Pi szám azért lenne tökéletes ilyen célokra, mivel tudjuk róla, hogy olyan mint, a szerelem: irracionális és nagyon fontos. A humort mellőzve, irracionális mivoltából következik, hogy végtelen és nem szakaszos, vagyis a számjegyek között nem igen van minta.
A legtöbb nem kriptográfiai RNG algoritmus hasonló elven működik. Adott egy generáló függvény, amit inicializálni kell egy kezdőértékkel és inicializálás után „véletlen” számok sorozatát fogja ontani magából az algoritmus. Azonban, ha tudom a kezdőértéket, akkor már nem is véletlen a generálás. Ideális esetben az inicializációs értéknek is véletlennek kellene lennie, de ez felveti a „tyúk vagy tojás volt előbb” klasszikus problémát.
A probléma áthidalására több módszer is létezik.
Az egyik módszer az, hogy idő alapján inicializálunk. A legtöbb számítógépben van valós idejű óra a dátum és idő tárolásához, illetve a modern (kb. 10 évnél fiatalabb) PC rendszerekben van integrálva egy nagy felbontású időzítő, amely egy másodpercet legalább 10 millió részre bont. Ha az időt másodpercben számítjuk egy fix dátumhoz képest (Pl: 1970.01.01 00:00 UNIX EPOCH esetén), akkor mindig más véletlen számot kapunk az inicializációs pillanattól függően. Ha ezt még kiegészítjük a nagy felbontású időzítő adatával, akkor jó közelítéssel kitalálhatatlan az inicializációs érték, de elméleti síkon lehetséges, mivel az idő rendszer megvalósítástól függően piszkálható.
A másik módszer az, hogy a környezetből mintavételezünk zajt. Minden analóg-digitális átalakítási módszernek a technológiából adódóan van némi hibája. Ez általában problémát jelent, de itt kifejezetten hasznos, mivel a zaj a környezet elektromágneses tulajdonságaiból származik (rádióhullámok, elektromos vezetékek, kozmikus sugárzás, stb…). Ha kifejezetten a környezeti zajt mintavételezzük, akkor használhatjuk a mintát inicializációs értéknek. A módszer problémája, hogy egyes környezetek zajosabbak, mint mások, így vannak kevésbé alkalmas és nagyon alkalmas környezetek. Éppen ezért az ilyen generátorok a saját zajforrásukat mintavételezik.
Az utóbbi megvalósítás előnye, hogy hardveres és szoftveresen nem piszkálható. Ilyen véletlenszám-generátort tartalmaz az alaplapra csatlakozó TPM modul is, ami az operációs rendszertől függetlenül generálja a számokat.
C# és .NET esetén a System névtérben található Random osztály felelős az RNG funkciókért. Azonban ez "csak" RNG célokra használható, kriptográfiai alkalmazásra nem.
Kriptográfiai célokra a RandomNumberGenerator osztály statikus metódusai alkalmazhatóak. Az osztály az alábbi statikus metódusokat definiálja:
public static void Fill (Span<byte> data);
Feltölt egy byte tömböt vagy egy byte span-t generált értékekkel.
public static byte[] GetBytes (int count);
A paraméterben megadott számú bye-ot állít elő, amit egy tömbben ad vissza.
public static int GetInt32 (int toExclusive);
public static int GetInt32 (int fromInclusive, int toExclusive);
Egy egész számot generál kriptográfiailag biztos módon. Az egyparaméteres változatában a felső limit adható meg. Ebben az esetben az alsó limit értéke 0. A kétparaméteres változatában az első paraméter az alsó limitet befolyásolja, a második pegig a felsőt.