El talón de Aquiles de la criptografía: cómo los PRNG pueden arruinar tu seguridad

'Kriptografiaren Akilesen orpoa: nola PRNGek zure segurtasuna hondatu dezaketen'

Celia Catalán



A02:2021 - Kriptografia hutsak – Zenbaki pseudoausazkoak (PRNG)

Sarrera

Programazioan zenbaki aleatorioen sortzea funtsezkoa da aplikazio askorentzat, batez ere kriptografian. Zenbaki aleatorioa aurreikusi edo aurreratu ezin dena da, eta horrek gakoen, tokenen edo sekretu gisa mantendu behar den edozein balioren sorrera segurua bermatzen du.

Bi motatako aleatorio zenbaki sortzaile (RNG, ingelesezko sigletan) daude:

1. Zenbaki pseudo-aleatorioen sortzaileak (PRNG): Algoritmo deterministak erabiltzen dituzte, eta, nahiz eta aleatorioak diruditen zenbaki-sekuentziak ekoizten dituzten, hasierako egoera edo haziaren ezagutza badago, aurreikusteko modukoak dira. Hori arriskutsua da kriptografia testuinguruetan, erasotzaile batek sekuentzia erreproduzitu eta balio sentikorrak aurreikusteko aukera izango bailuke.

2. Benetako aleatorio zenbaki sortzaileak (TRNG): Fenomeno fisiko ezustekoetan oinarrituta, hala nola erradiazio elektromagnetikoa edo zarata termikoa, sortzaile hauek askoz seguruagoak dira, aurreikusi ezin direlako.

Ahultasuna PRNG ez seguruen edo gaizki inplementatuta dauden sistemetan erabiltzen direnean sortzen da. Erasotzaile batek sortutako zenbakiak aurreikusi ahal baditu, sistemetako segurtasuna hautsi dezake, gako kriptografikoak deribatu, komunikazio seguruak atzitu edo babestutako baliabideetara sarbidea lortu.

Harreman hau ausazkotasun eta segurtasun aren artean da OWASPek kriptografia akatsak, hala nola ausazko zenbaki seguruak ez direnak sortzea, segurtasuneko kezka nagusien artean sartzen dituen arrazoietako bat.

Tekniko Sarrera

Zenbaki Pseudoaleatorioen (PRNG) Generazio Algoritmo bat determinista den sistema bat da, hazi izeneko balio hasierako bat funtzio matematiko definitu baten bidez transformatzen duena zenbaki sekuentzia bat sortzeko, itxuraz aleatorioak diruditenak. Hala ere, aleatorietate hau soilik azalekoa da, izan ere, sekuentzia hasierako hazitik erabat zehaztuta dago. Honek esan nahi du algoritmo beraren bi kasu, baldin eta hazi berberarekin hasita badaude, zenbaki sekuentzia identiko bat sortuko dutela. Nahiz eta propietate hau erabilgarria izan dezakeen zenbait testuingurutan, hala nola erreproduzigarriak diren simulazioetan, oso arazo handia da kriptografian, non aurreikuspenak segurtasunaren oinarrizko printzipioak ahultzen dituen.

Kriptografia segurtasunaren ikuspegitik, garrantzi handia ematen zaio prozesuetan, hala nola gakoen sortzean, hasierako bideratzaileetan eta nonce-an, erabiltzen diren zenbaki aleatorioen kalitateari eta iragartzeari. PRNG tradizionalak, hala nola, kongruentzial linealak (LCG), erasoei aurre egiteko ahulak dira, matematikako egitura sinplea eta hazietan erabilitako entropia gutxi dela eta. Generatzaile hauek, normalean, erasotzaile batek inferitu dezakeen, denbora-txartelak bezalako balio iragartzaileetan oinarritzen dira.

Tradizional PRNGetatik desberdin, kriptografiaz seguratutako zenbaki pseudoaleatorioen sortzaileak (CSPRNG) erasoaldien aurrean irauteko diseinatuta daude, baita euren barne egoera partzialki agerian uzten denean edo sekuentziaren irteera anitzak atzitzen direnean ere. CSPRNGek entropia iturri sendoagoak erabiltzen dituzte, hardwarean oinarritutako zenbaki pseudoaleatorioen sortzaile bat izan daiteke edo sistema iragazgaitzen prozesuak, eta algoritmo kriptografiko aurreratuak aplikatzen dituzte, blokeen zifratuetan edo hash funtzioetan oinarritutakoak, sekuentziaren iragazgaitasuna bermatzeko.

Ahultasun nagusiak

Klabe kriptografikoen sortzean aurreikusgarritasuna: PRNG seguru ez direnak aurreikusgarritasunak klabe kriptografikoen sortzea arriskuan jartzen du. Erasotzaile batek S_0 erabilitako haziaren inferentzia egin dezake, generatorren irteeren analisi baten bidez edo timestamp bezalako balio aurreikusgarri batean oinarritutako hazi bat asmatuz, eta horrela lotutako klabe pribatuak berregin ditzake, mezuak deszifratuz edo iruzurrezko sinadurak eginez. Arazo honek historikoki RSA eta ECC bezalako algoritmoak eragin ditu, non klabeen kalitatea zuzenean zenbaki aleatorioen kalitatearen araberakoa den.

Erabilitako edo aurreikusteko nonceak: AES-GCM edo ChaCha20-Poly1305 bezalako sistema kriptografikoetan, nonce bera (mezu bakoitzeko zenbaki bakarra) erabiltzeak datuen konfidentzialtasuna eta osotasuna arriskuan jartzen ditu. PRNG batek N aurreikusteko nonceak sortzen baditu edo balioak berrerabiltzen baditu espazio murritz batean talka egiteagatik, erasotzaile batek diferentzia analisiaren bidez testu laua berreskuratzeko moduko erasoei ekin diezaioke. Kasu nabarmen bat WPA2 inplementazioan nonceen berrerabiltzea da, KRACK bezalako erasoei aukera eman ziona.

JWT saio ahulak: JSON Web Token (JWT) tokenek balio bakar eta aleatorioen menpe daude, hauek erreplikatu edo asmatzea saihesteko. PRNG ez segurua saio identifikatzaileak edo sinadura balio aurreikusgarriak sortzen baditu, erasotzaile batek baliozko tokenak faltsutzeko aukera izango luke babestutako sistemetara sartzeko. Adibidez, zenbaki pseudoaleatorio aurreikusgarrien bidez eratorritako gakoetan oinarritutako HMAC sinadura batek ahalegin konputazional murriztua duen ordezkapen erasoa ahalbidetu dezake.

Handshake protokoloetan arazoak: TLS eta SSH bezalako protokoloek balio aleatorioen menpe daude saioak bakarrak izan daitezen eta erasotzaile batek erreproduzitu ez ditzan. Handshake-an erabiltzen diren zenbaki pseudoaleatorioak aurreikusteko modukoak badira, erasotzaile batek "replay" erasoei ekin diezaioke edo gako ahulak berriro negoziatzeko behartzen ahalko du, kanalaren konfidentzialtasuna arriskuan jarriz. Hori SSL/TLS bertsio zaharretan agerian geratu zen, PRNG eskasak erabiltzen zituztenak.

Seguru vs. ez segurua sortzeko konparazioa

"Ekoizpena hiru pauso nagusitan banatu daiteke:"

1. Hasierako haziaren lortzea:

Segurtasun eza duen generazioan, haziak iturri erraz aurreikustekoetatik deribatu ohi dira, hala nola timestamp bat, prozesu identifikatzailea (PID) edo baita balio konstante bat ere. Adibidez, generador congruential lineal batek une honetan segundoetan denbora erabil dezake, eta horrek nabarmen murrizten du erasotzailearentzako bilaketa espazioa. Bestalde, generazio seguruan, haziak entropia iturri sendo batetik dator, sistema eragileak bildu dituen barne egoerak bezala. Honek bermatzen du haziak ez direla aurreikustekoak eta erreproduzitzekoak.

2. Barne egoeraren kalkulua:

PRNG ez segurua hasierako haziaren transformazioa matematikako operazio sinpleen bidez egiten du, hala nola biderkaketak edo moduluko baturak, zeinak, ageriko aleatorioak sortzen dituzten arren, analisi nahikoa eginez gero, detektatzeko patroiak aurkezten dituzten. Aldiz, generatzaile seguruek algoritmo kriptografikoak aplikatzen dituzte, hala nola hash funtzioak edo blokeen enkriptatzeak, zeinak barne egoera itzultzeko handia diren erresistentzia dute.

3. Zenbaki-sekuentziaren ekoizpena:

Seguruak ez diren PRNGek sekuentziako zenbaki bakoitza azkar baina deterministako formulen bidez sortzen dute, eta horrek etorkizuneko irteerak aurreikustea ahalbidetzen du, baldin eta egungo egoera ezagutzen bada. Adibidez, irteera batzuk jarraian behatuz, erasotzaile batek algoritmoa deduzitu eta hurrengoak aurreikusi ditzake (kasuen oso sinpleetan). Aldiz, seguruak diren sortzaileek zenbakiak sortzen dituzte barne egoeraren eta funtzionamenduan bildutako entropia gehigarriaren araberako transformazioak erabiliz, irteera bakoitza praktikan aurreikusi ezin dena bihurtuz.

Goazen kodeara...


Terminala

               
#include (stdio .h="")
#include (stdlib .h="")
#include (time .h="")

int sortu_ausazko_zenbaki() {
    static int hasieratu = 0;
       bada (!hasiarazi) {
        srand((unsigned int)time(NULL)); // (-- Timestamp-a hazi gisa erabiltzea
        hasieratuta = 1;
    }

    itzuli rand() % 100;
}

int main() {
    printf(Pseudoausazko zenbakiak sortzen:
);
    for (int i = 0; i (5,i++) {
        printf(%d\n, generate_random_number());
    }
    itzuli 0;
}

      
Hasieran time(NULL) erabiltzen da hazi gisa, srand funtzioaren bidez pseudo-aleatorioen zenbaki sortzailea timestamp-aren (epoko segunduak) balio eguneratuarekin hasieratzen da. Lehen begiratuan arrazoizkoa dirudien arren, denbora etengabe aldatzen denez, aurreikustekoa da. Erasotzaile batek programaren exekuzio unea ezagutzen badu, erraz kalkula dezake erabilitako hazia.

srand() aleatorioen sortzailea hasieratzen du hazi bat sortuz, aldiz rand() zenbaki aleatorio bat besterik ez du itzultzen, azken honek lineako kongruentzia sortzaile bat (LCG) erabiltzen du, matematikoki sinplea izanik eta iragazkiak aurreikusteko modukoak sortzen ditu.

Hasierako generatorrak haziaren hasieraketa behin bakarrik egiten du, inoiz ez da eguneratzen entropia berri batekin, eta horrek esan nahi du programaren exekuzio guztiek, epe labur batean, pseudoausazko zenbaki sekuentzia berberak sortuko dituztela, aurreikus daitezkeen talka batzuk sortuz.

Gainera, irteera espazioa mugatua da. rand() funtzioaren irteeraren tartea txikia da, normalean 0 eta 2^32-1 artean, eta adibidearen kasuan, modulo operadorearekin murrizten da. Indar brutuko erasoei aukera ematen die.

Horregatik, hurrengo hurbilketa proposatzen da balio posibleak modu seguruan sortzeko.
  • 'Syscall-en erabilera, hala nola getrandom(), Linux-ek emandako kriptografiaz segurua den entropia iturri bat da (glibc bertsioa 2.25 edo berriagoa behar du).'
  • Sistemaak getrandom() ez badu onartzen, /dev/urandom erabil daiteke kalitate antzeko zenbaki aleatorioak lortzeko. Windows sistemetan, funtzio baliokidea BCryptGenRandom izango litzateke.
  • Alternatiboki, RDRAND (Intel/AMD) duten CPUetan, _rdrand32_step erabil daiteke, hardwaretik zuzenean zenbakiak lortzeko aukera emanez.

Terminala

#sartu (fcntl.h)
#sartu (errno.h)
#sartu (katea.h)
#include (linux/random.h)
#include (sys/syscall.h)

int sortu_segurtasun_ausazko_zenbaki() {
    uint32_t random_number;

    // Usar syscall getrandom para obtener un número aleatorio seguro
    if (syscall(SYS_getrandom, random_number, sizeof(random_number), 0) == -1) {
        perror("Seguru aleatorio zenbaki bat sortzean errorea");
        irten(EXIT_FAILURE);
    }

    itzuli random_number % 100;
}

int main() {
    printf("Seguruak diren zenbaki aleatorioak sortzen:
");
    for (int i = 0; i ( 5; i++) {
        printf(%d\n, generate_secure_random_number());
    }
    itzuli 0;
}
    
      

Daniel Puente, pentesterra Zerolynx-en
Itzuli blogera

Utzi iruzkin bat

Kontuan izan iruzkinak argitaratu aurretik onartu behar direla.