RANDOM(4)

NAZWA
random, urandom - urządzenia źródłowe liczb losowych jądra

SKŁADNIA
#include <linux/random.h>

int ioctl(fd, RNDżądanie, parametr);

OPIS
Specjalne urządzenia znakowe /dev/random i /dev/urandom (obecne w Linuksie od wersji 1.3.30) stanowią interfejs do wbudowanego w jądro generatora liczb losowych. Plik /dev/random ma numer główny urządzenia 1 i numer poboczny 8. Plik /dev/urandom ma numer główny urządzenia 1 i numer poboczny 9.

Generator liczb losowych zbiera szum środowiskowy ze sterowników urządzeń i innych źródeł do puli losowej. Generator przechowuje również szacunkową liczbę bitów szumu w puli losowej. Z puli tej tworzone są liczby losowe.

W trakcie odczytu, urządzenie /dev/random zwraca losowe bajty wyłącznie spośród oszacowanej liczby bitów szumu w puli. /dev/random nadaje się najlepiej do zastosowań, w których potrzebna jest losowość bardzo wysokiej jakości, jak np. jednorazowa maska lub generowanie kluczy. Jeśli pula losowa jest pusta, odczyt z /dev/random będzie wstrzymany do czasu zebrania dodatkowego szumu środowiskowego. Jeśli open(2) jest wywołane do /dev/random z flagą O_NONBLOCK, kolejne read(2) nie będzie blokowane, jeśli żądana liczba bajtów nie jest dostępna. W zamian zwracane są dostępne bajty. Jeśli nie ma dostępnych bajtów, read(2) zwróci -1, a errno ustawi się na EAGAIN.

Odczyt z urządzenia /dev/urandom zwróci tyle bajtów, ile zażądano. W efekcie, jeśli nie ma wystarczającego chaosu w puli losowej, do utworzenia żądanych bajtów jest używany generator pseudolosowy. Zwracane wartości są wówczas teoretycznie narażone na atak kryptograficzny w stosunku do algorytmów wykorzystywanych przez sterownik. Wiedza na ten temat nie jest dostępna w obecnych niezastrzeżonych publikacjach, ale istnieje teoretyczna możliwość przeprowadzenia takiego ataku. Jeśli jest to problemem w przypadku Twojego programu, użyj /dev/random. O_NONBLOCK nie ma wpływu przy korzystaniu z /dev/urandom. Przy wywoływaniu read(2) dla urządzenia /dev/urandom sygnały nie będą obsługiwane aż do utworzenia żądanych losowych bajtów. Od Linuksa 3.16, a read(2) z /dev/urandom zwróci co najwyżej 32 MB. read(2) z /dev/random zwróci nie więcej niż 512 bajtów (przed jądrami Linux w wersji 2.6.12 - 340 bajtów). Pisanie do /dev/random lub /dev/urandom zaktualizuje pulę entropii za pomocą pisanych danych, lecz nie zwiększy poziomu entropii. Oznacza to, że będzie to miało wpływ na odczyt z obu plików, lecz nie uczyni odczytu z /dev/random szybszym.

  Użycie
Jeśli nie jest pewne, czy należy użyć /dev/random, czy dev/urandom, to najprawdopodobniej powinno się użyć tego ostatniego. Generalna zasada jest taka, że /dev/urandom powinno być używane do wszystkiego, z wyjątkiem długoterminowych kluczy GPG/SSL/SSH. Jeśli plik puli losowej jest przechowywany pomiędzy ponownymi uruchomieniami, zgodnie z poniższymi zaleceniami (czynią to wszystkie główne dystrybucje Linuksa od co najmniej 2000 roku), wyjście jest kryptograficznie bezpieczne w stosunku do atakujących bez dostępu do lokalnego roota, zaraz po przeładowaniu go w sekwencji rozruchowej i odnosi się w całości do sieciowych kluczy szyfrujących sesji. Ponieważ odczyt z /dev/random może nie być płynny, użytkownicy będą go z reguły chcieli otworzyć w trybie nieblokującym (lub przeprowadzać odczyt z czasem oczekiwania) i udostępniać jakiś typ powiadomienia dla użytkownika, jeśli oczekiwana losowość nie jest od razu dostępna. Generator liczb losowych jądra jest zaprojektowany do tworzenia niewielkiej ilości ziarna (ang. seed) o wysokiej jakości, do użycia z kryptograficznym generatorem liczb pseudolosowych (ang. cryptographic pseudo-random number generator - CPRNG). Głównym celem było bezpieczeństwo, nie szybkość, i jest on kiepsko przystosowany do tworzenia dużej ilości danych losowych. Użytkownicy powinni odczytywać niewielkie ilości ziarna z /dev/urandom (i /dev/random) - niepotrzebne odczytywanie dużych ilości danych z tych urządzeń będzie miało negatywny wpływ na innych użytkowników urządzeń. Ilość ziarna potrzebna do wygenerowania klucza kryptograficznego zależy od efektywnego rozmiaru klucza. Na przykład, 3072-bitowy klucz prywatny RSA lub Diffiego-Hellmana ma efektywny rozmiar klucza 128-bitów (wymaga około 2^128 operacji do złamania), więc generator klucza potrzebuje jedynie 128 bitów (16 bajtów) ziarna z /dev/random. O ile niewielki margines bezpieczeństwa powyżej tego minimum jest zrozumiały, jako ochrona przed słabościami algorytmu CPRNG, nie istnieje aktualnie algorytm kryptograficzny zdolny zapewnić więcej niż 256 bitów bezpieczeństwa, więc jeśli jakiś program odczytuje więcej niż 256 bitów (32 bajtów) z losowego ziarna jądra na pojedyncze wywołanie lub na rozsądny interwał ponownego tworzenia ziarna (co najmniej minuta), to jest to oznaka, że jego kryptografia nie jest umiejętnie zaimplementowana.

  Konfiguracja
Jeśli w systemie nie ma plików /dev/random i /dev/urandom, można je utworzyć przy użyciu następujących poleceń:
    mknod -m 666 /dev/random c 1 8
    mknod -m 666 /dev/urandom c 1 9
    chown root:root /dev/random /dev/urandom
Gdy Linux uruchamiany jest przy niewielkim udziale operatora, pula losowa może być w dość przewidywalnym stanie. Faktyczna ilość szumu w puli losowej jest wówczas poniżej ilości szacowanej. Aby przeciwdziałać temu efektowi, pomocne jest zapamiętywanie informacji o puli losowej pomiędzy kolejnymi uruchomieniami systemu. Aby działo się to automatycznie, należy dodać wiersze do stosownych skryptów startowych Linuksa:
    echo "Inicjowanie generatora liczb losowych..."
    random_seed=/var/run/random-seed
    # Przechowanie wartości losowej od jednego startu systemu
    # do kolejnego startu. Ładowanie oraz późniejsze zachowywanie
    # całej puli losowej.    if [ -f $random_seed ]; then
        cat $random_seed >/dev/urandom
    else
        touch $random_seed
    fi
    chmod 600 $random_seed
    poolfile=/proc/sys/kernel/random/poolsize
    [ -r $poolfile ] && bits=$(cat $poolfile) || bits=4096
    bytes=$(expr $bits / 8)
    dd if=/dev/urandom of=$random_seed count=1 bs=$bytes
Trzeba również dodać następujące wiersze do stosownego skryptu uruchamianego podczas zamykania systemu Linuksa:
    # Przechowanie losowych danych pomiędzy wyłączeniem a włączeniem
    # komputera. Zachowywanie puli losowej generatora.
    echo "Zachowywanie puli losowej..."
    random_seed=/var/run/random-seed
    touch $random_seed
    chmod 600 $random_seed
    poolfile=/proc/sys/kernel/random/poolsize
    [ -r $poolfile ] && bits=$(cat $poolfile) || bits=4096
    bytes=$(expr $bits / 8)
    dd if=/dev/urandom of=$random_seed count=1 bs=$bytes
W powyższych przykładach zakładamy, że Linux jest w wersji 2.6.0 lub nowszej, gdzie /proc/sys/kernel/random/poolsize zwraca rozmiar puli entropii w bitach (zob. niżej).

  Interfejs /proc
Pliki w katalogu /proc/sys/kernel/random (obecnym od wersji 2.3.16) są dodatkowym interfejsem do urządzenia /dev/random.

Plik z prawami tylko do odczytu entropy_avail dostarcza dostępną pulę losową. Zazwyczaj będzie to 4096 (bitów), całość dostępnej puli.

Plik poolsize zawiera rozmiar puli losowej. Format tego pliku zależy od wersji jądra.

    Linux 2.4:
        Plik podaje rozmiar puli losowej w bajtach. Zazwyczaj - 512 (bajtów). Plik jest zapisywalny i może być zmieniony na dowolną wartość, dla której dostępny jest algorytm. Obecnie możliwe wartości to: 32, 64, 128, 256, 512, 1024 lub 2048.

    Linux 2.6:
        Plik jest dostępny tylko do odczytu i podaje rozmiar puli losowej w bitach. Zawiera wartość 4096.

Plik read_wakeup_threshold zawiera liczbę bitów entropii potrzebnej do obudzenia procesu, który zasnął, czekając na entropię z pliku /dev/random. Domyślnie - 64. Plik write_wakeup_threshold zawiera liczbę bitów entropii poniżej której zostanie uśpiony proces, który wykona select(2) lub poll(2), aby otworzyć do zapisu urządzenie /dev/random. Wartości te mogą być zmienione przez zapis do tych plików.

Pliki tylko do odczytu uuid i boot_id zawierają losowe łańcuchy znaków, takie jak 6fd5a44b-35f4-4ad4-a9b9-6b9be13e1fe9. Pierwszy z tych plików jest generowany na nowo przy każdym odczycie, a drugi jest generowany tylko raz.

  Interfejs ioctl(2)
Następujące żądania ioctl(2) są zdefiniowane na deskryptorach plików połączonych z /dev/random lub /dev/urandom. Wszystkie przeprowadzone żądania wpływają na wejściową pulę entropii zarówno /dev/random jak i /dev/urandom. Możliwość CAP_SYS_ADMIN jest wymagana przez wszystkie żądania za wyjątkiem RNDGETENTCNT.

RNDGETENTCNT
    Zbiera wartość entropii z puli wejściowej, zawartość będzie taka sama jak pliku entropy_avail w katalogu proc. Wyniki zostaną przechowane w liczbie całkowitej wskazanej przez argument.

RNDADDTOENTCNT
    Zwiększa lub zmniejsza wartość entropii z puli wejściowej o wartość wskazaną przez argument.

RNDGETPOOL
    Usunięte w Linuksie 2.6.9

RNDADDENTROPY
    Dodaje dodatkową entropię do puli wejściowej, zwiększając wartość entropii. Różni się to od zapisu do /dev/random lub /dev/urandom, które dodaje pewne dane, lecz nie zwiększa wartości entropii. Używana jest poniższa struktura:

        struct rand_pool_info {
            int    wartość_entropii;
            int    wiel_buf;
            __u32  buf[0];
        };

    Wartość_entropii to wartość dodawana (lub odejmowana) od wartości entropii, buf to bufor o wielkości wiel_buf dodawany do puli entropii.

RNDZAPENTCNT, RNDCLEARPOOL
    Zeruje wielkość entropii we wszystkich pulach i dodaje do nich pewne dane systemowe (np. rzeczywisty czas trwania - tzw. wall clock).

PLIKI
/dev/random
/dev/urandom

ZOBACZ TAKŻE
getrandom(2), mknod(1)
RFC 1750, "Randomness Recommendations for Security"

O STRONIE
Angielska wersja tej strony pochodzi z wydania 4.05 projektu Linux man-pages. Opis projektu, informacje dotyczące zgłaszania błędów, oraz najnowszą wersję oryginału można znaleźć pod adresem https://www.kernel.org/doc/man-pages/.

TŁUMACZENIE
Autorami polskiego tłumaczenia niniejszej strony podręcznika man są: Paweł Olszewski (PTM) <alder@civic.amg.net.pl>, Robert Luberda (PTM) <robert@debian.org> i Michał Kułach <michal.kulach@gmail.com>.

Polskie tłumaczenie jest częścią projektu manpages-pl; uwagi, pomoc, zgłaszanie błędów na stronie http://sourceforge.net/projects/manpages-pl/. Jest zgodne z wersją 4.05 oryginału.