Generování náhodných čísel je proces, při kterém algoritmus nebo zařízení produkuje posloupnost hodnot, které nelze předvídat. Náhodná čísla se využívají v mnoha oblastech informatiky a matematiky, například:

  • Statistika
  • Kryptografie
  • Generování herních prvků (např. náhodné mapy, losování)
  • Bezpečnostní tokeny, hesla, klíče

Přestože mluvíme o „náhodě“, tak získání doopravdy náhodného čísla je nesmírně obtížné a pro většinu problémů se jedná o přílišný nadstandard. Stačí u nich vygenerovat pouze čísla, která se blíží náhodnému číslu - tzv. pseudonáhodná číslo.

Generování pravých náhodných čísel (TRNG)

Pravá náhodná čísla (TRNG – True Random Number Generator) jsou čísla odvozená z fyzikálních jevů, které jsou skutečně náhodné, například:

  • Termální šum v elektronice
  • Radioaktivní rozpad
  • Atmosférický šum

Výhody

  • nelze je předpovědět
  • vhodné pro silně bezpečnostní aplikace

Nevýhody:

  • nákladnější hardware
  • nižší rychlost generování
  • obtížná dostupnost v běžných systémech

Generování pseudonáhodných čísel (PRNG)

V praxi se využívají téměř vždy pseudonáhodné generátory (PRNG – Pseudo Random Number Generator).

Charakteristiky PRNG:

  • generují deterministickou posloupnost čísel na základě počáteční hodnoty (seed)
  • stejný seed → stejná posloupnost čísel
  • běží velmi rychle a nevyžadují speciální hardware

Seed (Semínko)

Jedná se o počáteční číslo, které ovlivňuje sekvenci generovaných čísel. Pokud by se povedlo útočníkovi toto číslo odhalit, tak je schopen plně zrekonstruovat vygenerovanou sekvenci čísel.

PRNG není skutečně náhodný, ale pokud má dobré vlastnosti, jeho výstup se statisticky tváří náhodně.

Kvalita generátoru náhodných čísel

U pseudonánhodných generátorů je potřeba, aby generovaly co nejkvalitnější pseudonáhodné posloupnosti čísel. Pro zajištění kvality jsou přítomny dva testy:

  • Next-bit test
  • State-compromised test

Next-bit test

Pokud jsou známé všechny dosavadní bity výstupu, neměli bychom být schopni předpovědět další bit s pravděpodobností vyšší než 50 %. To je zásadní požadavek například v kryptografii.

State-compromise test

Pokud dojde ke kompromitaci vnitřního stavu generátoru (například únik hodnoty seedu nebo paměti aplikace):

  • útočník by neměl být schopen zpětně dopočítat předchozí výstupy
  • ani předpovědět budoucí výstupy

Běžné PRNG tyto vlastnosti často nemají, což je zásadní problém u aplikací, které vyžadují bezpečnost (klíče, tokeny, hesla). Pro generování kryptograficky bezpečných pseudonáhodných čísel je pak nutné využít speciální generátory. V C# lze k tomuto účelu využít například RandomNumberGenerator (z namespace System.Security.Cryptography).

Generování náhodných čísel v C#

new Random()

Nejznámější způsob generování pseudonáhodných čísel.

Ukázka použití:

var rnd = new Random();
int number = rnd.Next(0, 100); // číslo 0–99

Nevýhody této implementace:

  • Random není thread-safe
  • při více instancích vytvořených rychle za sebou se seedují stejným timestampem → generují stejné sekvence
  • není vhodný pro bezpečnostní účely

Ukázka problému:

var rnd1 = new Random();
var rnd2 = new Random();
Console.WriteLine(rnd1.Next()); // např. 123456
Console.WriteLine(rnd2.Next()); // často stejná hodnota!

Warning

Neexistuje jediný důvod proč tuto implementaci v aktuální době využívat. Vždy je lepší využít Random.Shared.

Random.Shared

Od .NET 6 existuje nová implementace random - Random.Shared:

int number = Random.Shared.Next(0, 100);

Výhody:

  • thread-safe
  • sdílená instance → šetří paměť
  • rychlejší než opakované vytváření nových instancí

Stále však není kryptograficky bezpečná. Lze ji využít pro běžné náhodné úlohy (např. hry, simulace).

Kryptograficky bezpečné náhodné hodnoty

Pro kryptografii nebo generování tajných dat (tokeny, hesla) je vhodné v C# využívat RandomNumberGenerator:

using System.Security.Cryptography;
 
byte[] bytes = new byte[32];
RandomNumberGenerator.Fill(bytes); // Například 32 náhodných bajtů

Pokud je potřeba vygenerovat například náhodný řetězec (base64):

string randomString = Convert.ToBase64String(bytes); Console.WriteLine(randomString);