Puncte:0

CSPRNG în Javascript?

drapel cn

Încerc să obțin un număr aleator, imprevizibil destul de lung (± 20-25 de cifre) folosind Javascript (creat de clientul utilizatorului) cât mai rapid și ușor posibil. Este această soluție suficient de fiabilă, robustă și sigură?

Când pagina online este deschisă, marca temporală din 13 cifre este stocată. Un cronometru determină numărul de milisecunde înainte ca utilizatorul să facă clic pe „OK” (să presupunem că are de citit un text scurt sau orice altceva de făcut). O colecție de 100 de „pixeli” invizibili (1*1px HTML se întinde) este creată cu culori RGBA inițiale fixate aleatoriu (A=0=transparență).

 fie d = Data.acum(); // marcaj temporal 13 cifre
 fie n = 100 // numărul de „pixeli” 
 lasă pixeli = ''

 pentru (i=0; i<n; i++) {
    fie r = Math.floor(Math.random() * 256); 
    fie g = Math.floor(Math.random() * 256); 
    fie b = Math.floor(Math.random() * 256);
    fie c = 'rgba('+r+','+g+','+b+',0)'
    pixeli += '<span id="pix'+i+'" style="background-color:'+c+'"></span>'
 }

Odată ce este gata, schimbăm aleatoriu culoarea fiecărui „pixel” la fiecare 100 de secundă

 lasă schimbareaColor = setInterval(funcție(){
    pentru (i=0; i<n; i++) {
        fie r = Math.floor(Math.random() * 256); 
        fie g = Math.floor(Math.random() * 256); 
        fie b = Math.floor(Math.random() * 256); 
        fie c = 'rgba('+r+','+g+','+b+',0)'
        document.getElementById('pix'+i).style.backgroundColor = c
    }
 },10);

Când utilizatorul face clic pe „OK”, funcția este oprită, este determinat un pixel aleatoriu și sunt găsite valorile RGB ale acestuia

fie x = Math.floor(Math.random() * n); // 39
let px = window.getComputedStyle(document.getElementById('pix'+x),null).backgroundColor
fie rgb = px.match(/\d+/g); // pix 39 = [21,13,152]

Apoi înmulțim fiecare valoare RGB cu x * un factor aleator [1 la 5]:

fie r = rgb[0]*(x*Math.floor(Math.random() * 5)+1), // 21 * 39 * 2 = 1638
    g = rgb[1]*(x*Math.floor(Math.random() * 5)+1), // 13 * 39 * 1 = 507
    b = rgb[2]*(x*Math.floor(Math.random() * 5)+1) // 152 * 39 * 4 = 23712

Adăugând x + temporizatorul + un extras aleatoriu al marcajului de timp obținem:

fie t = Data.now()-d; // temporizator la clic
fie p = Math.floor(Math.random() * 4)+3;    
fie z = d.toString().substr(-p) // ultima valoare a marcajului temporal xx (3->7)

fie val = x+''+r+g+b+''+t+z // 39 1368 507 23712 1348 55601

Apoi amestecăm aleatoriu rezultatul:

function shuffle(a) {
  fie r = a.lungime, temp, rand;
  în timp ce (0 !== r) {
    rand = Math.floor(Math.random() * r);
    r -= 1;
    temp = a[r];
    a[r] = a[rand];
    a[rand] = temp;
  }
  returnează a; // 39136850723712134855601 -> 25851963017738613021534
}

  Teste -> consola
  17:22:34 pix #39 = [21,13,152] 9348234523267751239843
  17:22:42 pix #39 = [21,13,152] 109715237240854257137
  17:23:02 pix #39 = [21,13,152] 100889146450039658553439

Dacă avem nevoie de un rezultat mai lung (50, 100 de cifre) putem crea 500 de „pixeli” și alegem aleatoriu 10 dintre ei în loc de unul. Sau adăugați o valoare de entropie (mișcarea mouse-ului pe ecran: https://www.grc.com/r&d/js.htm) la valoarea obţinută. Tu ce crezi?

Eugene Styer avatar
drapel dz
De la: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random: Notă: Math.random() nu oferă numere aleatoare securizate criptografic. Nu le folosiți pentru nimic legat de securitate. Utilizați în schimb API-ul Web Crypto și, mai precis, metoda window.crypto.getRandomValues().
Maarten Bodewes avatar
drapel in
Problema cu această schemă este că `Math.random()` nu furnizează numere aleatorii; de obicei, este generat folosind o semințe de 32 de biți care poate fi ușor de prezis. Deci, singura intrare care pare complet aleatorie este timpul dintre începerea calculelor și utilizatorul apăsând [OK]. Ah, și includeți un „Date()”, care nu este deloc aleatoriu. Cât de aleatoriu este aceasta depinde mai mult de sistem decât de orice altceva presupun. Mă aștept cel puțin ca cineva care poate programa un script să înceapă calculul la un anumit moment și aproape instantaneu ar putea forța să fie foarte non-aleatoriu.
Maarten Bodewes avatar
drapel in
[Acest lucru ar fi mult mai aleatoriu](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues)
drapel ph
Utilizarea pixelilor colorați nu oferă nicio funcționalitate mai sus de stocarea acelor valori într-o matrice.
Puncte:1
drapel fr

Matematică.aleatorie nu este un PRNG sigur din punct de vedere criptografic. De exemplu, Firefox folosește un generator bazat pe XorShift, care își va scurge întreaga stare după doar câteva apeluri. Prin urmare, nu creați cu adevărat pixeli aleatori aici; doar alegeți valori bazate pe aceeași sămânță anterioară.

MDN descrie funcția Web Cryptography API pentru generarea de numere aleatoare securizate criptografic. Dacă lucrați în Node.js, vine cu funcții încorporate care fac același lucru. Acestea sunt concepute pentru a implementa CSPRNG-uri, de obicei cel de sistem, pe care ar trebui să le utilizați dacă nu sunteți sigur că aveți nevoie de altceva. Acestea vor fi potrivite pentru aproape toate nevoile criptografice, iar utilizarea sistemului CSPRNG este recomandată cu tărie de majoritatea criptografilor.

Dacă aveai nevoie de ceva reproductibil, poți folosi ceva de genul ChaCha20 cu o cheie și nonce generate din sistemul CSPRNG sau un HMAC-DRBG cu SHA-2 sau SHA-3. Cu toate acestea, acest lucru nu este necesar în majoritatea situațiilor și este mai bine, atunci când este posibil, să evitați implementarea propriei criptografii în favoarea implementărilor cunoscute și de încredere, așa că dacă ați avea nevoie de acest lucru, ar fi mai bine să utilizați o implementare cunoscută.

Wolden avatar
drapel cn
Multumesc pentru raspuns si comentarii. Sunt de acord pentru slăbiciunea Math.random, dar dincolo de pozițiile de principiu, face ca aceste rezultate obținute să fie previzibile și, prin urmare, nesigure. Dacă da, de ce și cum? Vă mulțumesc pentru ajutor în înțelegere, nu sunt altceva decât un începător în criptografie ;-)
Wolden avatar
drapel cn
așa cum se arată în ultimele mele 3 rânduri (teste->consolă) odată ce funcția este oprită, marcajul de timp și pixelul sunt definite. Am apăsat de multe ori pe butonul OK până am găsit 3 rezultate pentru aceeași pixă (#39): cu aceleași valori RGB obțin 3 rezultate foarte diferite. Sunt ele previzibile (adică într-o „listă de rezultate posibile” previzibilă)?
bk2204 avatar
drapel fr
Ele sunt probabil suficient de predictibile încât această abordare să fie supusă forței brute. Doar pentru că „pare aleatoriu” nu înseamnă că nu este previzibil. Nu voi face o criptoanaliză completă a acestei abordări, deoarece cred că utilizarea sistemului CSPRNG este, evident, mai bună și este alegerea logică, dar dacă utilizați `Math.random` ca sursă aleatorie unde aveți nevoie de un CSPRNG, voi solicitați un CVE împotriva software-ului dvs.
Wolden avatar
drapel cn
Multumesc pentru explicatii :-)
Puncte:0
drapel cn

Am folosit de mai sus de 6 ori funcția Math.random(), una pentru a obține o valoare 0->255 (r,g,b), una pentru a obține o valoare 0->100 (număr de pixeli) și altele pentru a obțineți valori mai mici (adică 3->5 pentru marca temporală)

Valoarea 0->255 (r,g,b) este acum luată din

    las rand = new Uint8Array(3); // 3 vals 0 -> 255
    window.crypto.getRandomValues(rand);
    fie r = rand[0]; 
    fie g = rand[1]; 
    fie b = rand[2];

și valoarea 0->100 (număr de pixeli) de la

    let pix = new Uint8Array(1);
    window.crypto.getRandomValues(pix);
    fie v = Math.floor(pix[0]/2.55); // val 0->100

După ce am înlocuit toate funcțiile Math.random() cu aceste noi implementări, crezi că este mai sigur și mai fiabil/rezistent la atacuri?

Postează un răspuns

Majoritatea oamenilor nu înțeleg că a pune multe întrebări deblochează învățarea și îmbunătățește legătura interpersonală. În studiile lui Alison, de exemplu, deși oamenii își puteau aminti cu exactitate câte întrebări au fost puse în conversațiile lor, ei nu au intuit legătura dintre întrebări și apreciere. În patru studii, în care participanții au fost implicați în conversații ei înșiși sau au citit transcrieri ale conversațiilor altora, oamenii au avut tendința să nu realizeze că întrebarea ar influența – sau ar fi influențat – nivelul de prietenie dintre conversatori.