Criptare în PHP. Criptați, decriptați datele folosind o cheie în PHP Criptare și chei de autentificare

  • Traducere
  • Tutorial

De la traducător: în procesul de programare, nu uit niciodată că sunt periculos de incompetent în criptografie și sfătuiesc pe toată lumea să plece de la această teză (ei bine, poate cu excepția dvs. și a tipului ăla tare de acolo). Cu toate acestea, într-un fel sau altul, în procesul muncii apar probleme legate de protecția datelor și trebuie rezolvate. Prin urmare, vă aduc în atenție o traducere a unui articol al dezvoltatorului finlandez Timo H, care mi s-a părut destul de interesantă și utilă.

Acesta este un ghid rapid despre cum să evitați capcanele comune cu criptarea simetrică în PHP.

Vom lua în considerare cazul în care datele sunt procesate pe partea serverului (în special, criptarea are loc pe server, iar datele pot fi primite, de exemplu, de la client sub formă de text clar, parolă etc.), care este un caz tipic pentru aplicațiile PHP.

Informațiile din acest ghid nu trebuie utilizate pentru a crea conexiuni de rețea criptate care au cerințe mai complexe. Pentru astfel de cazuri, trebuie să utilizați spionaj sau TLS.

Desigur, recomandările date aici nu sunt „singura modalitate posibilă” de a organiza criptarea în PHP. Scopul acestui ghid este de a încerca să lase mai puțin loc pentru greșeli și decizii dificile, ambigue.

Funcții de criptare în PHP

Utilizați extensiile Mcrypt sau OpenSSL.

Algoritm de criptare și modul său de funcționare, cod unic (vector de inițializare)

Utilizați AES-256 în modul CTR cu un cod unic aleatoriu ( aproximativ traducere: nonce). AES este un standard, așa că puteți utiliza funcțiile oricăreia dintre extensii - Mcrypt sau OpenSSL.

Generați întotdeauna un nou cod unic. În acest caz, trebuie să utilizați o sursă sigură criptografic de numere aleatorii. Citiți mai jos puțin mai multe despre generarea numerelor aleatoare. Codul unic nu este un secret și poate fi concatenat cu text cifrat pentru transmitere și decriptare ulterioară.

Codul unic trebuie să aibă o lungime de 128 de biți (16 octeți), doar un șir de octeți fără nicio codificare.

În extensia Mcrypt, AES este cunoscut ca Rijndael-128 ( aproximativ transl.: în ciuda faptului că vorbim despre AES-256, aceasta nu este o eroare. AES-256 != Rijndael-256). În OpenSSL, respectiv, AES-256-CTR.

Exemplu de utilizare Mcrypt:
Exemplu OpenSSL:
Verificați dacă criptarea funcționează corect folosind vectori de testare ( aproximativ traducere: pentru AES-256-CTR vezi paragraful F.5.5 de la pagina 57).

Pentru modul CTR, există unele restricții privind volumul total de date criptate. Este posibil să nu întâlniți acest lucru în practică, dar rețineți că nu ar trebui să criptați mai mult de 2^64 de octeți de date cu o singură cheie, indiferent dacă este un mesaj lung sau mai multe mesaje scurte.

Modul CTR rămâne stabil doar dacă nu utilizați același cod unic cu aceeași cheie. Din acest motiv, este important să generați coduri unice utilizând o sursă criptografic puternică de aleatorie. În plus, aceasta înseamnă că nu ar trebui să criptați mai mult de 2^64 de mesaje cu o singură cheie. Deoarece lungimea codului unic este de 128 de biți, limita numărului de mesaje (și codurile unice corespunzătoare) de 2^128/2 este importantă din cauza Paradoxului Zilei de Naștere ( aproximativ traducere:).

Și amintiți-vă că criptarea nu va ascunde faptul că multe date trimiteți. Ca exemplu de caz extrem, dacă criptați mesajele care conțin doar „da” sau „nu”, evident criptarea nu va ascunde informațiile respective.

Autentificarea datelor

Verificați întotdeauna autenticitatea și integritatea datelor.
Pentru a face acest lucru, utilizați MAC după criptare. Acestea. Mai întâi datele sunt criptate, iar apoi HMAC-SHA-256 este preluat din textul cifrat rezultat, inclusiv textul cifrat în sine și codul unic.

Când decriptați, verificați mai întâi HMAC-ul folosind un algoritm de comparare care este rezistent la atacurile de sincronizare. Nu comparați direct $user_submitted_mac și $calculated_mac folosind operatorii de comparație == sau ===. Este chiar mai bine să folosiți „HMAC double check”.

Dacă verificarea HMAC are succes, decriptarea se poate face în siguranță. Dacă HMAC nu este adecvat, opriți imediat.

Chei de criptare și autentificare

În mod ideal, utilizați chei derivate dintr-o sursă criptografic puternică de aleatorie. AES-256 necesită 32 de octeți de date aleatorii (un șir „brut” - o secvență de biți fără a utiliza nicio codificare).

Dacă aplicația rulează sub versiunea PHP sub 5.5, care nu are o implementare încorporată a PBKDF2, atunci va trebui să utilizați propria implementare în PHP, un exemplu al cărei exemplu poate fi găsit aici: https://defuse. ca/php-pbkdf2.htm. Rețineți că bazarea pe propria implementare poate să nu rezolve cheia în mod corespunzător, așa cum o face funcția încorporată hash_pbkdf2().

Nu utilizați aceeași cheie pentru criptare și autentificare. După cum sa menționat mai sus, sunt necesari 32 de octeți pentru cheia de criptare și 32 de octeți pentru cheia de autentificare (HMAC). Cu PBKDF2 puteți lua 64 de octeți din parolă și puteți utiliza, să zicem, primii 32 de octeți ca cheie de criptare, iar restul de 32 de octeți pentru cheia de autentificare.

Dacă parolele dvs. sunt stocate într-un fișier, de exemplu, ca șir HEX, nu le re-codificați înainte de a le introduce în funcțiile de criptare. În schimb, utilizați PBKDF2 pentru a converti cheile codificate HEX direct într-o cheie de criptare sau autentificare de înaltă calitate. Sau utilizați SHA-256 fără ieșire suplimentară de codare (doar un șir de 32 de octeți) pentru a hash parolele. Utilizarea hashingului obișnuit al parolei oferă suficientă entropie. Mai multe detalii sunt oferite în paragrafele următoare.

Întinderea cheii

În primul rând, ar trebui să evitați utilizarea tastelor cu entropie scăzută. Dar totuși, dacă trebuie să utilizați, de exemplu, parole de utilizator, atunci cu siguranță trebuie să utilizați PBKDF2 cu un număr mare de iterații pentru a maximiza securitatea cheii.

Unul dintre parametrii PBKDF2 este numărul de iterații de hashing. Și cu cât este mai mare, cu atât este mai mare securitatea cheii pe care te poți baza. Dacă codul rulează pe o platformă pe 64 de biți, utilizați SHA-512 ca algoritm de hashing pentru PBKDF2. Pentru o platformă pe 32 de biți, utilizați SHA-256.

Cu toate acestea, nu este posibil să se utilizeze un număr relativ mare de iterații în aplicațiile online din cauza riscului unui atac DoS. Prin urmare, calitatea cheii nu va fi la fel de mare ca în aplicațiile offline, care își pot permite un număr mare de iterații fără un astfel de risc. De regulă, pentru aplicațiile online, un astfel de număr de iterații hashing este selectat, astfel încât PBKDF2 să nu dureze mai mult de 100 ms.

În cazul în care puteți utiliza parole cu entropie mare, nu este necesar să o întindeți, așa cum ați face pentru parolele cu entropie scăzută. De exemplu, dacă creați o „encryption_master_key” și o „auth_master_key” folosind /dev/urandom, atunci nu este deloc nevoie de PBKDF2. Doar asigurați-vă că utilizați cheile ca secvențe de biți, fără nicio codificare.

În plus, cu PBKDF2 nu este dificil să obțineți atât cheile de criptare, cât și cheile de autentificare dintr-o singură parolă principală (utilizați doar un număr mic de iterații sau chiar una). Acest lucru este util dacă aveți o singură „parolă principală” folosită atât pentru criptare, cât și pentru autentificare.

Depozitarea și gestionarea cheilor

Cel mai bun lucru este să utilizați un dispozitiv separat de stocare a cheilor (HSM).

Dacă acest lucru nu este posibil, atunci pentru a complica atacul, se poate folosi criptarea fișierului cheie sau a fișierului de configurare (care stochează cheile reale de criptare/autentificare) folosind o cheie stocată într-o locație separată (în afara directorului principal sau a rădăcinii site-ului) . De exemplu, puteți utiliza o variabilă de mediu Apache în httpd.conf pentru a stoca cheia necesară pentru a decripta fișierul de chei real:
SetEnv keyfile_key crypto_strong_high_entropy_key # Puteți accesa această variabilă în PHP folosind $_SERVER["keyfile_key"] # Restul configurației
Acum, dacă fișierele de la rădăcina site-ului și de mai jos, inclusiv fișierele cu chei, sunt compromise (de exemplu, dacă se scurge o copie de rezervă), datele criptate vor rămâne în siguranță, deoarece cheia stocată în variabila de mediu nu a fost compromisă. Este important să ne amintim că fișierele httpd.conf ar trebui să fie copiate separat și să nu compromită variabila keyfile_key prin, de exemplu, rezultatul lui phpinfo().

Dacă utilizați un fișier în loc de un parametru de configurare, este posibil să organizați rotația tastelor. În cel mai rău caz, dacă un adversar a obținut cheile dvs. de criptare și autentificare fără a fi observat, atunci rotirea cheilor la anumite intervale poate limita accesul acestora (presupunând că nu poate obține chei noi). Această tehnică va ajuta la reducerea daunelor, deoarece inamicul nu va putea folosi cheile compromise la infinit.

Comprimarea datelor

În general, nu ar trebui să comprimați textul sursă înainte de a-l cripta. Acest lucru poate oferi inamicului un instrument suplimentar de analiză.

De exemplu, dacă stocați datele de sesiune în cookie-uri criptate, dintre care unele sunt furnizate de utilizator și unele reprezintă informații secrete, un adversar poate afla informații suplimentare despre secret prin trimiterea, ca utilizator obișnuit, a unor date special concepute și măsurarea modului în care se modifică lungimea textelor cifrate rezultate.

Textul este comprimat mai eficient dacă există zone care se repetă. Prin manipularea datelor utilizatorului, le puteți selecta astfel încât să coincidă parțial cu datele secrete. Cu cât potrivirea este mai mare, cu atât textul cifrat este mai mic. Acest tip de atac se numește CRIME.

Dacă nu aveți nevoie să comprimați datele, nu le comprima.

Mediul server

Ca regulă generală, nu ar trebui să găzduiți aplicații sensibile la securitate pe un server partajat. De exemplu, pe găzduire partajată, unde un adversar poate accesa o mașină virtuală pe același server fizic ca și tine.

Există diverse motive care fac din serverele partajate un loc dubios pentru a găzdui aplicații critice pentru securitate. De exemplu, recent au fost demonstrate atacuri între servere virtuale: eprint.iacr.org/2014/248.pdf. Acesta este un bun memento că tehnicile ofensive nu se degradează, ci mai degrabă sunt perfecționate și îmbunătățite în timp. Astfel de capcane trebuie întotdeauna luate în considerare.

Consultație de specialitate

Nu în ultimul rând, consultați un expert pentru a vă revizui codul de securitate.

(PHP 4, PHP 5, PHP 7)

crypt — Hashing unidirecțional de șiruri

Avertizare

Această funcție nu este (încă) în siguranță binară!

Descriere

criptă (șir $str [, string $sare]): șir

criptă() va returna un șir hash folosind algoritmul standard Unix DES sau algoritmi alternativi care pot fi disponibili pe sistem.

Parametrul de sare este opțional. In orice caz, criptă() creează un hash slab fără sare. PHP 5.6 sau o versiune ulterioară generează o eroare E_NOTICE fără aceasta. Asigurați-vă că specificați o sare suficient de puternică pentru o mai bună securitate.

password_hash() folosește un haș puternic, generează o sare puternică și aplică automat runde adecvate. password_hash() este un simplu criptă() wrapper și compatibil cu hash-urile de parole existente. Utilizarea de password_hash() e incurajat.

Unele sisteme de operare acceptă mai mult de un tip de hash. De fapt, uneori algoritmul standard bazat pe DES este înlocuit cu un algoritm bazat pe MD5. Tipul hash este declanșat de argumentul sare. Înainte de 5.3, PHP determina algoritmii disponibili la momentul instalării, pe baza criptei sistemului (). Dacă nu este furnizată nicio sare, PHP va genera automat fie o sare standard de două caractere (DES), fie o sare de douăsprezece caractere ( MD5), în funcție de disponibilitatea MD5 crypt(). PHP setează o constantă numită CRYPT_SALT_LENGTH care indică cea mai lungă sare valabilă permisă de hashurile disponibile.

Standardul bazat pe DES criptă() returnează sarea ca primele două caractere ale rezultatului. De asemenea, folosește doar primele opt caractere ale str , astfel încât șirurile mai lungi care încep cu aceleași opt caractere vor genera același rezultat (când se folosește aceeași sare).

Pe sistemele în care funcția crypt() acceptă mai multe tipuri de hash, următoarele constante sunt setate la 0 sau 1, în funcție de dacă tipul dat este disponibil:

  • CRYPT_STD_DES- Hash standard pe bază de DES cu o sare de două caractere din alfabetul „./0-9A-Za-z”. Folosirea caracterelor nevalide în salt va duce la eșecul crypt() .
  • CRYPT_EXT_DES- Hash extins bazat pe DES. „Sarea” este un șir de 9 caractere format dintr-un caracter de subliniere urmat de 4 octeți de număr de iterații și 4 octeți de sare. Acestea sunt codificate ca caractere imprimabile, 6 biți pe caracter, primul caracter cel mai puțin semnificativ. Valorile de la 0 la 63 sunt codificate ca „./0-9A-Za-z”. Folosirea caracterelor nevalide în salt va duce la eșecul crypt() .
  • CRYPT_MD5- Hashing MD5 cu o sare de douăsprezece caractere începând cu $1$
  • CRYPT_BLOWFISH- Blowfish hashing cu o sare, după cum urmează: „$2a$”, „$2x$” sau „$2y$”, un parametru de cost cu două cifre, „$” și 22 de caractere din alfabetul „./0-9A- Za-z”. Utilizarea caracterelor din afara acestui interval în sare va face ca crypt() să returneze un șir de lungime zero. Parametrul de cost cu două cifre este logaritmul de bază 2 al numărului de iterații pentru algoritmul de hashing bazat pe Blowfish și trebuie să fie în intervalul 04-31, valorile din afara acestui interval vor duce la eșecul crypt() . Versiunile de PHP înainte de 5.3.7 acceptă doar „$2a$” ca prefix de sare: PHP 5.3.7 a introdus noile prefixe pentru a remedia o deficiență de securitate în implementarea Blowfish. Consultați pentru detalii complete despre remedierea de securitate, dar pentru a rezuma, dezvoltatorii care vizează numai PHP 5.3.7 și versiuni ulterioare ar trebui să folosească „$2y$” în detrimentul „$2a$”.
  • CRYPT_SHA256- SHA-256 hash cu o sare de șaisprezece caractere prefixată cu $5$. Dacă șirul de sare începe cu „rounds=
  • CRYPT_SHA512- SHA-512 hash cu o sare de șaisprezece caractere prefixată cu $6$. Dacă șirul de sare începe cu „rounds= $", valoarea numerică a lui N este folosită pentru a indica de câte ori trebuie executată bucla de hashing, la fel ca parametrul cost pe Blowfish. Numărul implicit de runde este 5000, există un minim de 1000 și un maxim de 999.999.999. Orice selecție de N în afara acestui interval va fi trunchiată la cea mai apropiată limită.

Începând cu PHP 5.3.0, PHP conține propria sa implementare și o va folosi dacă sistemul nu are suport pentru unul sau mai mulți algoritmi.

Parametrii

Șirul care urmează să fie hashing.

Prudență

Folosind CRYPT_BLOWFISH algoritm, va avea ca rezultat trunchierea parametrului str la o lungime maximă de 72 de caractere.

Un șir de sare opțional pe care să se bazeze hashingul. Dacă nu este furnizat, comportamentul este definit de implementarea algoritmului și poate duce la rezultate neașteptate.

Valori returnate

Returnează șirul hash sau un șir care este mai scurt de 13 caractere și este garantat că va diferi de sarea la eșec.

Avertizare

La validarea parolelor, o funcție de comparare a șirurilor care nu este vulnerabilă la atacurile de sincronizare ar trebui utilizată pentru a compara rezultatul criptă() la hash-ul cunoscut anterior. PHP 5.6 și versiunile ulterioare furnizează hash_equals()în acest scop.

Jurnalul modificărilor

Versiune Descriere
5.6.5 Când șirul de eșec „*0” este dat ca sare, „*1” va fi returnat acum pentru coerență cu alte implementări de criptă. Înainte de această versiune, PHP 5.6 returna incorect un hash DES.
5.6.0 Activați avertismentul de securitate E_NOTICE dacă sarea este omisă.
5.5.21 Când șirul de eșec „*0” este dat ca sare, „*1” va fi returnat acum pentru coerență cu alte implementări de criptă. Înainte de această versiune, PHP 5.5 (și ramurile anterioare) returna incorect un hash DES.
5.3.7 Adăugat 2x$și $2y$ Moduri Blowfish pentru a face față potențialelor atacuri de biți înalți.
5.3.2 S-a adăugat cripta SHA-256 și SHA-512 bazată pe implementarea Ulrich Drepper.
5.3.2 S-a remediat comportamentul Blowfish la runde nevalide pentru a returna șirul „eșec” („*0” sau „*1”), în loc să se întoarcă la DES.
5.3.0 PHP conține acum propria sa implementare pentru cripta MD5, Standard DES, Extended DES și algoritmii Blowfish și o va folosi dacă sistemul nu are suport pentru unul sau mai mulți algoritmi.

Exemple

Exemplul #1 criptă() exemple

$parola_hashed = crypt("parola mea"); // lasă sarea să fie generată automat

/* Ar trebui să treceți toate rezultatele crypt() ca sare pentru a compara a
parola, pentru a evita problemele atunci când sunt utilizați diferiți algoritmi de hashing. (La fel de
scrie mai sus, hashingul standard al parolelor bazat pe DES folosește o sare de 2 caractere,
dar hashingul bazat pe MD5 folosește 12.) */
if (hash_equals ($hashed_parola , cripta ($user_input , $hashed_parola ))) (
echo "Parola verificată!" ;
}
?>

Exemplul #2 Utilizarea criptă() cu htpasswd

// Setați parola
$parola = "parola mea" ;

// Obține hash-ul, lăsând sarea să fie generată automat
$hash = cripta($parola);
?>

Exemplul #3 Utilizarea criptă() cu diferite tipuri de hash

/* Aceste săruri sunt doar exemple și nu ar trebui să fie folosite literal în codul dvs.
Ar trebui să generați o sare distinctă, formatată corect pentru fiecare parolă.
*/
dacă (CRYPT_STD_DES == 1 ) (
echo "Standard DES: " . criptă ("rasmuslerdorf" , "rl") . „\n” ;
}

dacă (CRYPT_EXT_DES == 1 ) (
echo "DES extins: " . criptă ("rasmuslerdorf" , "_J9..rasm" ) . „\n” ;
}

dacă (CRYPT_MD5 == 1) (
ecou "MD5: " . criptă ("rasmuslerdorf" , "$1$rasmusle$") . „\n” ;
}

dacă (CRYPT_BLOWFISH == 1 ) (
ecou "Blowfish: " . cripta("rasmuslerdorf" , „$2a$07$folosește un șir stupid pentru sare$”). „\n” ;
}

dacă (CRYPT_SHA256 == 1) (
ecou "SHA-256: " . cripta("rasmuslerdorf" , „$5$rotunde=5000$folosește un șir prostesc pentru sare$”). „\n” ;
}

dacă (CRYPT_SHA512 == 1) (
ecou "SHA-512: " . cripta("rasmuslerdorf" , „$6$rotunde=5000$folosește niște șiruri stupide pentru sare$”). „\n” ;
}
?>

Orice informație poate fi criptată sau decriptată, inclusiv folosind PHP. Acest limbaj are multe capacități de criptare a datelor, de la simplu la complex.

Să ne uităm la metodele de bază de criptare

baza64- vă permite să criptați și să decriptați datele folosind algoritmul MIME base64. Nu folosește chei și este adesea folosit pentru a ascunde link-uri în PHP.

Exemple:
//criptați textul
$text = "Link";
echo base64_encode($text); //Produce: PGEgaHJlZj0iIyI+0KHRgdGL0LvQutCwPC9hPg==
//decriptare
echo base64_decode("PGEgaHJlZj0iIyI+0KHRgdGL0LvQutCwPC9hPg==");
?>

După cum puteți vedea, am folosit mai întâi operația base64_encode și am obținut cifrul: PGEgaHJlZj0iIyI+0KHRgdGL0LvQutCwPC9hPg==, și apoi l-a înlocuit în base64_decode și a primit linkul înapoi.

md5- vă permite să hashați datele în mod unilateral. Adică, spre deosebire de base64, nu le veți mai putea decripta înapoi. Deseori md5 este folosit pentru a stoca parole într-o bază de date, dar recent combinația criptată md5 a devenit ușor de găsit în tabelele de decriptare, oferite cu amabilitate de multe site-uri și algoritmi. Prin urmare, pentru a stoca parolele md5, este mai bine să înlocuiți algoritmii cu Blowfish.

Exemplu:

//criptați textul
echo md5 ("combinație");
?>

Criptare cheie

Iar ultimul exemplu de criptare/decriptare despre care am vrut să vorbesc folosește o cheie (ca parolă). Adică, transmiteți o cheie unică funcției de criptare, iar codul este criptat împreună cu aceasta. Pentru a decripta, trebuie să furnizați funcției codul criptat și o cheie pe care numai dumneavoastră o cunoașteți. Un exemplu de utilizare a funcțiilor din partea de jos a codului.

funcția __encode($text, $key) (



$enc_text=base64_encode(mcrypt_generic($td,$iv.$text));
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
returnează $enc_text; ) )
funcția strToHex($șir) (
$hex="";
pentru ($i=0; $i< strlen($string); $i++) { $hex .= dechex(ord($string[$i])); }
returnează $hex; )
funcția __decode($text, $key) (
$td = mcrypt_module_open("triplede", "", "cfb", "");
$iv_size = mcrypt_enc_get_iv_size($td);
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
if (mcrypt_generic_init ($td, $key, $iv) != -1) (
$decode_text = substr(mdecrypt_generic($td, base64_decode($text)),$iv_size);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
returnează $decode_text; ) )
funcția hexToStr($hex) (
$string="";
pentru ($i=0; $i< strlen($hex)-1; $i+=2) { $string .= chr(hexdec($hex[$i].$hex[$i+1])); }
returnează $șir; )

$str = "Chile care trebuie criptate!
Prin cheie";
$cod = strToHex(__encode($str, "My#key-do-36-simvolov"));
echo „Cod criptat: „.$code”.
";

$str = __decode(hexToStr($code), "My#key-do-36-simvolov");
echo „Cod decriptat: „.$str.”
";
?>

Puteți cripta conținutul html. Lungimea cheii nu trebuie să depășească 36 de caractere.

Această metodă poate fi folosită pentru a cripta unele date și a le plasa într-un fișier txt sau o bază de date și pentru a le primi folosind decriptarea cu o cheie.

Desigur, orice cod poate fi decriptat/piratat și aceasta nu face excepție, așa că folosiți metode puternice de criptare.

Unul dintre adevărurile de bază ale criptografiei este că nu ar trebui să inventezi nimic în acest domeniu decât dacă ești un profesionist. Acest lucru este parțial adevărat, deoarece tot ce este mai bun a fost de mult inventat, suferit și folosit de zeci de ani în domeniul tehnologiei informației. Cealaltă parte a adevărului este că dezvoltarea unui anumit domeniu de cunoaștere are loc numai cu un aflux constant de idei proaspete și soluții originale în el.

Din motive evidente, nu ne vom ținti pe giganții criptografiei industriale precum AES, ci ne vom arunca, ca să spunem așa, în propria noastră cercetare criptografică cu blackjack și bucurie.

Parțial pentru că este interesant, parțial pentru că modelând ceva propriu și comparându-l cu standardele recunoscute, vedeți clar contrastul, soluțiile eficiente și omisiunile absolute și înțelegeți la ce vă puteți strădui pentru a îmbunătăți eficiența.

Dar destulă apă deja.

Să presupunem că aplicația noastră web este scrisă în PHP, are nevoie de criptare reversibilă și credem că ne putem scrie propriul sistem de criptare.

Deci, să scriem propriul nostru sistem de criptare reversibilă cu chei private și publice, unul care va avea următoarele caracteristici ale unui algoritm criptografic mai mult sau mai puțin sigur:

  1. Prezența simbolurilor de zgomot în cifra finală.
  2. Informațiile din fiecare canal de expeditor-destinație vor fi criptate folosind o cheie privată, iar funcția de potrivire va fi unică pentru fiecare cheie.
  3. Fiecare mesaj va primi un cod digest - un cod unic care este o funcție a cheii private și a mesajului original. Acest lucru este necesar pentru a obține unicitatea funcției de potrivire „simbol sursă”.<=>simbol codificat” nu numai pentru canalul „Emițător-Receptor”, ci și pentru fiecare mesaj individual.

    Astfel, chiar dacă ne imaginăm că corespondența simbolurilor codificate și originale pentru un anumit mesaj a devenit cunoscută prin utilizarea analizei criptografice, de exemplu, analiza frecvenței, aceasta nu oferă preferințe atunci când studiem un alt mesaj.

  4. Pentru a complica analiza de frecvență, vom codifica fiecare simbol inițial al mesajului cu două simboluri de criptare.
Deci ce s-a întâmplat.

De fapt, puteți vedea rezultatul final

Clasa SymCoder include metode de criptare și decriptare.

Criptarea este realizată prin metoda code(), care ia mesajul original ca intrare.

Aici, un mesaj din tabelul de corespondență generat în tab_coded creează un mesaj criptat, diluat de-a lungul marginilor și în interior cu simboluri de zgomot.

Apropo, simbolurile de zgomot sunt unice pentru fiecare canal de destinație al expeditorului, deoarece sunt generate folosind cheia de canal, dar nu sunt unice pentru mesaje. Simbolurile folosite pentru criptare în code_symbols sunt unele semne de punctuație și simboluri precum %, @ etc.

Pentru fiecare simbol codificat, există două simboluri din code_symbols, din motive evidente că există de câteva ori mai puține dintre ele decât simbolurile codificate.

Tabelul de corespondență create_tab_coded este construit folosind o traducere a hash-ului cheii de mesaj într-o matrice cu numărul de elemente egal cu numărul de elemente din tabloul simbol de cod. Poziția de pornire pentru parcurgerea codurilor cu două caractere este, de asemenea, întotdeauna diferită și este asociată cu cheia de canal. Acest lucru face posibil să fim siguri că algoritmul de parcurgere a simbolurilor codificate și de potrivire a simbolurilor de cod cu acestea va fi întotdeauna diferit (sau este garantat că va fi adesea).

De exemplu, mesajul „hello world”, când este codificat, arată astfel:

Digest-a00bf11d-&?==&!&?.@.@=!=-.?&1.#&?=:.:.1%!&-%@&@%~&1^#=?%% .!%+.?.~=?..&?%&&:%~.#%@&1&1.#=?.#.?.!&1==&=.-=!

Și iată același mesaj, codificat din nou:

Digest-a00bf11d-=:.?=:&!.?.1&-=:=?.?.=.?.!&=%!=-%@=!%~.=^#.1%%. !%+=:.~.@..==%&&1%~.1%@=?.@.!&=.!&@=:&1.==:=!.1&:

Se poate observa că rezumatul aceluiași mesaj este același, dar cifrul devine diferit - simbolurile de zgomot sunt adăugate într-o potrivire arbitrară și într-o ordine arbitrară pentru fiecare nouă criptare.

Mesajele au redundanță, care scade pe măsură ce volumul mesajului crește, până la 10% zgomot (pentru cele mai scurte mesaje, zgomotul ajunge la 90% sau mai mult procent), lungimea minimă a unui mesaj criptat este de 116 caractere. Unul dintre dezavantajele acestei metode de criptare este că mesajele codificate sunt cel puțin dublate.

Decodificarea constă în traducerea inversă a formei „simbol cod” - simbolul original cu zgomot tăiat din mesaj. Care ar putea fi cheia? Practic, orice șir care este unic pentru fiecare pereche destinație-receptor.

De exemplu, dacă creați un messenger cu criptare a mesajelor, atunci cea mai simplă versiune a cheii private ar putea fi md5($user_id_1. $salt. $user_id_2), atunci cheia va fi unică pentru fiecare canal de mesaj.

Să presupunem că trebuie să faceți schimb de date între două servere. Pentru a proteja datele de traficul interceptat, datele sunt criptate. Ei bine, de exemplu, transferul de acțiuni în cadrul unei rețele bot. Aceasta este ceea ce în esență nu este criptare, ci se numește codare, iar funcțiile binecunoscute sunt folosite pentru a decoda un astfel de cod.

Ca un alt exemplu de pseudo-criptare, voi da un exemplu de „criptare” a parolelor în baza de date a unui CMS - acolo parolele nu sunt criptate în md5() sau , ci pur și simplu codificate prin base64. Acestea. Când baza de date este scursă, nu va fi dificil pentru un hacker să decripteze toate parolele folosind funcția PHP încorporată base64_decode().

Trebuie să transmitem date fără să ne îngrijorăm că cineva va putea intercepta textul și îl va decripta. PHP are un pachet popular de criptare a datelor numit Mcrypt, care oferă criptare bidirecțională (adică criptarea și decriptarea efectivă a datelor).

Mcrypt versiunea 2.4.7 acceptă următorii algoritmi de criptare simetrică: Blowfish, RC2, Safer-sk64 xtea, Cast-256, RC4, Safer-sk128, DES, RC4-iv, Serpent, Enigma, Rijndael-128, Threeway, Rijndael-192 , TripleDES, LOKI97, Rijndael-256, Twofish, Panama, Saferplus etc. Mai multe detalii despre fiecare algoritm sunt scrise pe Wikipedia.

Deoarece se utilizează criptarea simetrică, cheia trebuie să fie cunoscută de ambele părți și păstrată secretă.

Exemplu de criptare și decriptare a unui șir

mcrypt_module_open("des", "", "ecb", "")
Această funcție deschide modulul algoritm și modul utilizat. Pentru acest exemplu, algoritmul DES este în modul ECB.

$key = substr($cheie, 0, mcrypt_enc_get_key_size($td));
Dimensiunea maximă a cheii trebuie obținută prin apelarea funcției mcrypt_enc_get_key_size() și orice valoare mai mică decât aceasta va fi corectă.

$s = mcrypt_generic($td, $sursa);
La criptare, datele sunt umplute cu zero octeți pentru a se asigura că datele sunt de n * blocuri lungi. Mărimea blocului dimensiunea blocului este determinată de algoritm (pentru DES dimensiunea blocului este de 64 de biți). Prin urmare, la decriptare, „\0” poate apărea la sfârșitul liniei, care este eliminată de funcția trim()