Szyfrowanie w PHP. Szyfruj, deszyfruj dane za pomocą klucza w PHP. Klucze szyfrujące i uwierzytelniające

  • Tłumaczenie
  • Instruktaż

Od tłumacza: w trakcie programowania nigdy nie zapominam, że jestem niebezpiecznie niekompetentny w kryptografii i radzę wszystkim, aby kontynuowali tę tezę (no, może z wyjątkiem ciebie i tego fajnego gościa). Jednak tak czy inaczej, w trakcie pracy pojawiają się problemy związane z ochroną danych i należy je rozwiązać. Dlatego zwracam uwagę na tłumaczenie artykułu fińskiego programisty Timo H, który wydał mi się dość interesujący i przydatny.

To jest krótki przewodnik, jak uniknąć typowych pułapek związanych z szyfrowaniem symetrycznym w PHP.

Rozważymy przypadek, gdy dane przetwarzane są po stronie serwera (w szczególności na serwerze następuje szyfrowanie, a dane można otrzymać np. od klienta w postaci czystego tekstu, hasła itp.), co jest typowym przypadkiem dla aplikacji PHP.

Informacje zawarte w tym przewodniku nie powinny być wykorzystywane do tworzenia szyfrowanych połączeń sieciowych, które mają bardziej złożone wymagania. W takich przypadkach musisz użyć szpiegowania lub TLS.

Oczywiście podane tutaj zalecenia nie są „jedynym możliwym sposobem” zorganizowania szyfrowania w PHP. Celem tego przewodnika jest pozostawienie mniej miejsca na błędy i trudne, niejednoznaczne decyzje.

Funkcje szyfrowania w PHP

Użyj rozszerzeń Mcrypt lub OpenSSL.

Algorytm szyfrowania i sposób jego działania, kod jednorazowy (wektor inicjujący)

Użyj AES-256 w trybie CTR z losowym kodem jednorazowym ( około. tłumaczenie: nonce). AES jest standardem, można więc skorzystać z funkcji dowolnego z rozszerzeń – Mcrypt lub OpenSSL.

Zawsze generuj nowy kod jednorazowy. W takim przypadku musisz skorzystać z kryptograficznie bezpiecznego źródła liczb losowych. Przeczytaj trochę więcej o generowaniu liczb losowych poniżej. Kod jednorazowy nie jest tajemnicą i można go połączyć z tekstem zaszyfrowanym w celu transmisji, a następnie odszyfrowania.

Kod jednorazowy musi mieć długość 128 bitów (16 bajtów) i być po prostu ciągiem bajtów bez żadnego kodowania.

W rozszerzeniu Mcrypt AES jest znany jako Rijndael-128 ( około. tłumacz: pomimo tego, że mówimy o AES-256, nie jest to błąd. AES-256!= Rijndael-256). W OpenSSL odpowiednio AES-256-CTR.

Przykład użycia Mcrypt:
Przykład OpenSSL:
Sprawdź, czy szyfrowanie działa poprawnie, używając wektorów testowych ( około. tłumaczenie: dla AES-256-CTR patrz paragraf F.5.5 na stronie 57).

W trybie CTR obowiązują pewne ograniczenia dotyczące całkowitej objętości zaszyfrowanych danych. W praktyce możesz się z tym nie spotkać, ale pamiętaj, że jednym kluczem nie należy szyfrować więcej niż 2^64 bajtów danych, niezależnie od tego, czy jest to jedna długa wiadomość, czy wiele krótkich.

Tryb CTR pozostaje stabilny tylko wtedy, gdy nie używasz tego samego kodu jednorazowego z tym samym kluczem. Z tego powodu ważne jest generowanie kodów jednorazowych przy użyciu silnego kryptograficznie źródła losowości. Dodatkowo oznacza to, że nie należy szyfrować więcej niż 2^64 wiadomości jednym kluczem. Ponieważ długość kodu jednorazowego wynosi 128 bitów, ograniczenie liczby wiadomości (i odpowiadających im kodów jednorazowych) wynoszące 2^128/2 jest ważne ze względu na paradoks urodzin ( około. tłumaczenie:).

I pamiętaj, że szyfrowanie nie ukryje faktu, ile danych wysyłasz. Jako przykład skrajnego przypadku, jeśli szyfrujesz wiadomości zawierające tylko „tak” lub „nie”, oczywiście szyfrowanie nie ukryje tych informacji.

Uwierzytelnianie danych

Zawsze sprawdzaj autentyczność i integralność danych.
Aby to zrobić, użyj adresu MAC po zaszyfrowaniu. Te. Najpierw dane są szyfrowane, a następnie z powstałego tekstu zaszyfrowanego pobierany jest kod HMAC-SHA-256, obejmujący sam tekst zaszyfrowany i kod jednorazowy.

Podczas odszyfrowywania najpierw sprawdź HMAC przy użyciu algorytmu porównawczego odpornego na ataki czasowe. Nie porównuj bezpośrednio $user_submitted_mac i $calculated_mac za pomocą operatorów porównania == lub ===. Jeszcze lepiej jest użyć „podwójnego sprawdzenia HMAC”.

Jeśli sprawdzenie HMAC zakończy się pomyślnie, można bezpiecznie przeprowadzić deszyfrowanie. Jeśli HMAC nie jest odpowiedni, natychmiast wyłącz.

Klucze szyfrujące i uwierzytelniające

Najlepiej używać kluczy pochodzących z kryptograficznie silnego źródła losowości. AES-256 wymaga 32 bajtów losowych danych („surowy” ciąg znaków – sekwencja bitów bez użycia żadnego kodowania).

Jeśli aplikacja działa pod wersją PHP poniżej 5.5, która nie posiada wbudowanej implementacji PBKDF2, wówczas konieczne będzie skorzystanie z własnej implementacji w PHP, której przykład znajdziesz tutaj: https://defuse. ca/php-pbkdf2.htm. Należy pamiętać, że poleganie na własnej implementacji może nie spowodować prawidłowego rozpoznania klucza, jak robi to wbudowana funkcja hash_pbkdf2().

Nie używaj tego samego klucza do szyfrowania i uwierzytelniania. Jak wspomniano powyżej, wymagane są 32 bajty na klucz szyfrowania i 32 bajty na klucz uwierzytelniający (HMAC). Dzięki PBKDF2 możesz pobrać 64 bajty z hasła i użyć, powiedzmy, pierwszych 32 bajtów jako klucza szyfrującego, a pozostałe 32 bajty jako klucza uwierzytelniającego.

Jeśli Twoje hasła są przechowywane w pliku, na przykład jako ciąg HEX, nie koduj ich ponownie przed wprowadzeniem ich do funkcji szyfrujących. Zamiast tego użyj PBKDF2, aby przekonwertować klucze zakodowane w formacie HEX bezpośrednio na wysokiej jakości klucz szyfrowania lub uwierzytelniania. Lub użyj SHA-256 bez dodatkowego kodowania (tylko ciąg 32-bajtowy) do mieszania haseł. Używanie zwykłego mieszania haseł zapewnia wystarczającą entropię. Więcej szczegółów podano w poniższych akapitach.

Kluczowe rozciągnięcie

Po pierwsze, należy unikać używania kluczy o niskiej entropii. Ale nadal, jeśli musisz użyć na przykład haseł użytkowników, zdecydowanie musisz użyć PBKDF2 z dużą liczbą iteracji, aby zmaksymalizować bezpieczeństwo kluczy.

Jednym z parametrów PBKDF2 jest liczba iteracji mieszania. A im jest ona wyższa, tym na większe bezpieczeństwo klucza możesz liczyć. Jeśli Twój kod działa na platformie 64-bitowej, użyj SHA-512 jako algorytmu mieszającego dla PBKDF2. W przypadku platformy 32-bitowej użyj SHA-256.

Nie jest jednak możliwe zastosowanie stosunkowo dużej liczby iteracji w aplikacjach online ze względu na ryzyko ataku DoS. Dlatego jakość klucza nie będzie tak wysoka, jak w aplikacjach offline, które mogą pozwolić sobie na dużą liczbę iteracji bez takiego ryzyka. Z reguły dla aplikacji online dobierana jest taka liczba iteracji haszujących, aby PBKDF2 trwało nie dłużej niż 100 ms.

Jeśli możesz używać haseł o wysokiej entropii, nie jest konieczne rozciąganie ich tak, jak w przypadku haseł o niskiej entropii. Na przykład, jeśli utworzysz „klucz_główny_szyfrowania” i „klucz_główny_auth” za pomocą /dev/urandom, wówczas PBKDF2 w ogóle nie będzie potrzebny. Pamiętaj tylko, aby używać kluczy jako sekwencji bitów, bez żadnego kodowania.

Ponadto dzięki PBKDF2 nie jest trudno uzyskać zarówno klucze szyfrujące, jak i uwierzytelniające z jednego hasła głównego (wystarczy użyć niewielkiej liczby iteracji lub nawet jednej). Jest to przydatne, jeśli masz tylko jedno „hasło główne” używane zarówno do szyfrowania, jak i uwierzytelniania.

Przechowywanie kluczy i zarządzanie nimi

Najlepszym rozwiązaniem jest użycie osobnego, dedykowanego urządzenia do przechowywania kluczy (HSM).

Jeśli nie jest to możliwe, to aby skomplikować atak, można zastosować szyfrowanie pliku klucza lub pliku konfiguracyjnego (w którym przechowywane są rzeczywiste klucze szyfrowania/uwierzytelniania) przy użyciu klucza przechowywanego w osobnej lokalizacji (poza katalogiem domowym lub katalogiem głównym witryny) . Na przykład możesz użyć zmiennej środowiskowej Apache w pliku httpd.conf do przechowywania klucza potrzebnego do odszyfrowania rzeczywistego pliku kluczy:
SetEnv keyfile_key crypto_strong_high_entropy_key # Możesz uzyskać dostęp do tej zmiennej w PHP za pomocą $_SERVER["keyfile_key"] # Pozostała część konfiguracji
Teraz, jeśli pliki w katalogu głównym witryny i poniżej, w tym pliki z kluczami, zostaną naruszone (na przykład w wyniku wycieku kopii zapasowej), zaszyfrowane dane pozostaną bezpieczne, ponieważ klucz przechowywany w zmiennej środowiskowej nie został naruszony. Należy pamiętać, że kopie zapasowe plików httpd.conf powinny być tworzone oddzielnie i nie naruszać zmiennej keyfile_key, na przykład poprzez wyjście phpinfo().

Jeśli zamiast parametru konfiguracyjnego użyjesz pliku, możesz zorganizować rotację kluczy. W najgorszym przypadku, jeśli przeciwnik zdobędzie Twoje klucze szyfrowania i uwierzytelnienia niezauważony, wówczas rotacja kluczy w pewnych odstępach czasu może ograniczyć jego dostęp (zakładając, że nie będzie mógł uzyskać nowych kluczy). Ta technika pomoże zmniejszyć obrażenia, ponieważ wróg nie będzie mógł używać skompromitowanych kluczy w nieskończoność.

Kompresja danych

Ogólnie rzecz biorąc, nie należy kompresować tekstu źródłowego przed jego zaszyfrowaniem. Może to dać wrogowi dodatkowe narzędzie do analizy.

Na przykład, jeśli przechowujesz dane sesji w zaszyfrowanych plikach cookie, z których część jest dostarczana przez użytkownika, a część stanowi tajne informacje, przeciwnik może uzyskać dodatkowe informacje na temat sekretu, wysyłając, jako zwykły użytkownik, specjalnie spreparowane dane i mierzenie, jak zmienia się długość wynikowego tekstu zaszyfrowanego.

Tekst jest kompresowany efektywniej, jeśli występują w nim powtarzające się obszary. Manipulując danymi użytkownika, możesz je wybrać tak, aby częściowo pokrywały się z tajnymi danymi. Im większe dopasowanie, tym mniejszy wyjściowy tekst zaszyfrowany. Ten rodzaj ataku nazywa się PRZESTĘPSTWEM.

Jeśli nie masz pilnej potrzeby kompresowania danych, nie kompresuj ich.

Środowisko serwerowe

Ogólną zasadą jest, że nie należy hostować aplikacji wrażliwych na bezpieczeństwo na serwerze współdzielonym. Na przykład na hostingu współdzielonym, gdzie przeciwnik może uzyskać dostęp do maszyny wirtualnej na tym samym serwerze fizycznym co Ty.

Istnieje wiele powodów, które sprawiają, że serwery współdzielone są wątpliwym miejscem do hostowania aplikacji o krytycznym znaczeniu dla bezpieczeństwa. Na przykład ostatnio zademonstrowano ataki pomiędzy serwerami wirtualnymi: eprint.iacr.org/2014/248.pdf. To dobre przypomnienie, że techniki ofensywne nie ulegają degradacji, lecz z biegiem czasu są doskonalone i ulepszane. Zawsze należy brać pod uwagę takie pułapki.

Konsultacje eksperckie

Na koniec skonsultuj się z ekspertem, aby sprawdzić swój kod bezpieczeństwa.

(PHP 4, PHP 5, PHP 7)

crypt — Jednokierunkowe mieszanie ciągów

Ostrzeżenie

Ta funkcja nie jest (jeszcze) bezpieczna binarnie!

Opis

krypta (ciąg $str [, ciąg $sól]): strunowy

krypta() zwróci zaszyfrowany ciąg znaków przy użyciu standardowego algorytmu opartego na Unix DES lub alternatywnych algorytmów, które mogą być dostępne w systemie.

Parametr soli jest opcjonalny. Jednakże, krypta() tworzy słaby skrót bez soli. Bez tego PHP 5.6 lub nowszy zgłasza błąd E_NOTICE. Dla większego bezpieczeństwa upewnij się, że określono wystarczająco mocną sól.

hasło_hash() używa silnego skrótu, generuje silną sól i automatycznie stosuje odpowiednie rundy. hasło_hash() jest proste krypta() wrapper i kompatybilny z istniejącymi skrótami haseł. Zastosowanie hasło_hash() jest dobrze widziane.

Niektóre systemy operacyjne obsługują więcej niż jeden typ skrótu. W rzeczywistości czasami standardowy algorytm oparty na DES jest zastępowany algorytmem opartym na MD5. Typ skrótu jest wyzwalany przez argument salt. Przed wersją 5.3 PHP określało dostępne algorytmy podczas instalacji w oparciu o systemową funkcję crypt(). Jeśli nie podano soli, PHP automatycznie wygenerowało albo standardową sól dwuznakową (DES), albo dwunastoznakową ( MD5), w zależności od dostępności MD5 crypt(). PHP ustawia stałą o nazwie CRYPT_SALT_LENGTH co wskazuje najdłuższą prawidłową sól dozwoloną przez dostępne skróty.

Standard oparty na DES krypta() zwraca sól jako pierwsze dwa znaki wyniku. Używa również tylko pierwszych ośmiu znaków str , więc dłuższe ciągi rozpoczynające się od tych samych ośmiu znaków wygenerują ten sam wynik (jeśli zostanie użyta ta sama sól).

W systemach, w których funkcja crypt() obsługuje wiele typów skrótu, następujące stałe są ustawiane na 0 lub 1 w zależności od tego, czy dany typ jest dostępny:

  • CRYPT_STD_DES- Standardowy skrót oparty na DES z dwuznakową solą z alfabetu „./0-9A-Za-z”. Użycie nieprawidłowych znaków w soli spowoduje niepowodzenie funkcji crypt().
  • CRYPT_EXT_DES- Rozszerzony skrót oparty na DES. „Sól” to 9-znakowy ciąg składający się ze znaku podkreślenia, po którym następują 4 bajty liczby iteracji i 4 bajty soli. Są one kodowane jako znaki nadające się do wydruku, 6 bitów na znak, zaczynając od znaku najmniej znaczącego. Wartości od 0 do 63 są kodowane jako „./0-9A-Za-z”. Użycie nieprawidłowych znaków w soli spowoduje niepowodzenie funkcji crypt().
  • CRYPT_MD5- Hashowanie MD5 z dwunastoznakową solą zaczynającą się od 1 $
  • CRYPT_BLOWFISH- Mieszanie Blowfish z solą w następujący sposób: „$2a$”, „$2x$” lub „$2y$”, dwucyfrowy parametr kosztu, „$” i 22 znaki z alfabetu „./0-9A- Za-z”. Użycie w soli znaków spoza tego zakresu spowoduje, że funkcja crypt() zwróci ciąg znaków o zerowej długości. Dwucyfrowy parametr kosztu to logarytm o podstawie 2 liczby iteracji dla bazowego algorytmu mieszania opartego na Blowfish i musi mieścić się w zakresie 04-31, wartości spoza tego zakresu spowodują niepowodzenie funkcji crypt(). Wersje PHP starsze niż 5.3.7 obsługują tylko „$2a$” jako prefiks soli: PHP 5.3.7 wprowadziło nowe przedrostki, aby naprawić lukę w zabezpieczeniach implementacji Blowfish. Pełne informacje na temat poprawki bezpieczeństwa można znaleźć w artykule, ale podsumowując, programiści skupiający się wyłącznie na PHP 5.3.7 i nowszych powinni używać „$2y$” zamiast „$2a$”.
  • CRYPT_SHA256- Hash SHA-256 z szesnastoznakową solą poprzedzoną $5$. Jeśli ciąg soli zaczyna się od „rounds=
  • CRYPT_SHA512- Hash SHA-512 z szesnastoznakową solą poprzedzoną $6$. Jeśli ciąg soli zaczyna się od „rounds= $”, wartość liczbowa N służy do wskazania, ile razy należy wykonać pętlę mieszającą, podobnie jak parametr kosztu w Blowfish. Domyślna liczba rund to 5000, minimalna liczba wynosi 1000, a maksymalna to 999 999 999. Każdy wybór N spoza tego zakresu zostanie obcięty do najbliższego limitu.

Począwszy od PHP 5.3.0, PHP zawiera własną implementację i użyje jej, jeśli system nie obsługuje jednego lub więcej algorytmów.

Parametry

Ciąg, który ma zostać zaszyfrowany.

Ostrożność

Używając CRYPT_BLOWFISH algorytmu, spowoduje obcięcie parametru str do maksymalnej długości 72 znaków.

Opcjonalny ciąg soli, na którym opiera się mieszanie. Jeśli nie zostanie podany, zachowanie jest zdefiniowane przez implementację algorytmu i może prowadzić do nieoczekiwanych wyników.

Zwracane wartości

Zwraca ciąg zaszyfrowany lub ciąg krótszy niż 13 znaków, który w przypadku niepowodzenia gwarantuje różnicę od soli.

Ostrzeżenie

Podczas sprawdzania poprawności haseł należy użyć funkcji porównywania ciągów, która nie jest podatna na ataki czasowe, aby porównać dane wyjściowe krypta() do wcześniej znanego skrótu. PHP 5.6 i nowsze zapewnia hash_equals() w tym celu.

Dziennik zmian

Wersja Opis
5.6.5 Gdy jako sól zostanie podany ciąg błędu „*0”, „*1” zostanie teraz zwrócone w celu zapewnienia spójności z innymi implementacjami krypt. Przed tą wersją PHP 5.6 błędnie zwracał skrót DES.
5.6.0 Zgłoś ostrzeżenie bezpieczeństwa E_NOTICE, jeśli pominięto sól.
5.5.21 Gdy jako sól zostanie podany ciąg błędu „*0”, „*1” zostanie teraz zwrócone w celu zapewnienia spójności z innymi implementacjami krypt. Przed tą wersją PHP 5.5 (i wcześniejsze gałęzie) błędnie zwracały skrót DES.
5.3.7 Dodany $2x$ I 2 lata $ Tryby Blowfish do radzenia sobie z potencjalnymi atakami wysokobitowymi.
5.3.2 Dodano krypty SHA-256 i SHA-512 w oparciu o » implementację Ulricha Dreppera.
5.3.2 Naprawiono zachowanie Blowfisha w nieprawidłowych rundach polegające na zwracaniu ciągu znaków „niepowodzenie” („*0” lub „*1”) zamiast powracania do DES.
5.3.0 PHP zawiera teraz własną implementację algorytmów krypty MD5, standardowego DES, rozszerzonego DES i Blowfish i użyje jej, jeśli system nie obsługuje jednego lub więcej algorytmów.

Przykłady

Przykład 1 krypta() przykłady

$hashed_password = crypt("mojehasło"); // niech sól zostanie wygenerowana automatycznie

/* Powinieneś przekazać całe wyniki crypt() jako sól do porównania a
hasło, aby uniknąć problemów w przypadku stosowania różnych algorytmów mieszania. (Jak
jak jest napisane powyżej, standardowe hashowanie haseł oparte na DES używa 2-znakowej soli,
ale haszowanie oparte na MD5 używa 12.) */
if (hash_equals ($hashed_password , crypt ($user_input , $hashed_password ))) (
echo "Hasło zweryfikowane!" ;
}
?>

Przykład nr 2 Używanie krypta() z htpasswd

// Ustaw hasło
$hasło = "mojehasło" ;

// Pobierz skrót, pozwalając, aby sól została wygenerowana automatycznie
$hash = krypta($hasło);
?>

Przykład nr 3 Używanie krypta() z różnymi typami skrótów

/* Te sole są tylko przykładami i nie powinny być używane dosłownie w kodzie.
Dla każdego hasła powinieneś wygenerować odrębną, poprawnie sformatowaną sól.
*/
jeśli (CRYPT_STD_DES == 1 ) (
echo "Standardowy DES: " . krypta („rasmuslerdorf”, „rl”). "\N" ;
}

jeśli (CRYPT_EXT_DES == 1 ) (
echo "Rozszerzony DES: " . krypta („rasmuslerdorf” , „_J9..rasm”) . "\N" ;
}

jeśli (CRYPT_MD5 == 1 ) (
echo "MD5: ". krypta („rasmuslerdorf”, „$1$rasmusle$”) . "\N" ;
}

jeśli (CRYPT_BLOWFISH == 1 ) (
echo "Blowfish: " . krypta("rasmuslerdorf" , „$2a$07$przydatny głupi ciągforsalt$”) . "\N" ;
}

jeśli (CRYPT_SHA256 == 1 ) (
echo "SHA-256: ". krypta("rasmuslerdorf" , „5 $ rund = 5000 $ przydatnych głupich ciągów dla soli $”) . "\N" ;
}

jeśli (CRYPT_SHA512 == 1 ) (
echo "SHA-512: ". krypta("rasmuslerdorf" , „6 $ rund = 5000 $ przydatnych głupich ciągów dla soli $”) . "\N" ;
}
?>

Wszelkie informacje można zaszyfrować lub odszyfrować, w tym przy użyciu języka PHP. Język ten ma wiele możliwości szyfrowania danych, od prostych po złożone.

Przyjrzyjmy się podstawowym metodom szyfrowania

baza64- umożliwia szyfrowanie i deszyfrowanie danych przy użyciu algorytmu MIME base64. Nie używa kluczy i jest często używany do ukrywania linków w PHP.

Przykłady:
//zaszyfruj tekst
$tekst = "Link";
echo base64_encode($tekst); //Produkuje: PGEgaHJlZj0iIyI+0KHRgdGL0LvQutCwPC9hPg==
//deszyfrowanie
echo base64_decode("PGEgaHJlZj0iIyI+0KHRgdGL0LvQutCwPC9hPg==");
?>

Jak widać, najpierw użyliśmy operacji base64_encode i otrzymaliśmy szyfr: PGEgaHJlZj0iIyI+0KHRgdGL0LvQutCwPC9hPg==, a następnie podstawiłem go do base64_decode i otrzymałem link z powrotem.

md5- pozwala na jednostronne hashowanie danych. Oznacza to, że w przeciwieństwie do base64 nie będzie już można ich ponownie odszyfrować. Często md5 służy do przechowywania haseł w bazie danych, ale ostatnio zaszyfrowaną kombinację md5 można łatwo znaleźć w tabelach deszyfrujących, dzięki uprzejmości wielu witryn i algorytmów. Dlatego do przechowywania haseł md5 lepiej zastąpić algorytmy Blowfish.

Przykład:

//zaszyfruj tekst
echo md5("kombinacja");
?>

Szyfrowanie klucza

Ostatni przykład szyfrowania/deszyfrowania, o którym chciałem porozmawiać, wykorzystuje klucz (jako hasło). Oznacza to, że przekazujesz unikalny klucz do funkcji szyfrowania, a kod jest szyfrowany wraz z nim. Aby odszyfrować, musisz podać funkcji zaszyfrowany kod i klucz, który znasz tylko Ty. Przykład wykorzystania funkcji znajdujących się na samym dole kodu.

funkcja __encode($tekst, $klucz) (



$enc_text=base64_encode(mcrypt_generic($td,$iv.$text));
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
zwróć $enc_text; ) )
funkcja strToHex($string) (
$szesnastkowo="";
dla ($i=0; $i< strlen($string); $i++) { $hex .= dechex(ord($string[$i])); }
zwróć $hex; )
funkcja __decode($tekst, $klucz) (
$td = mcrypt_module_open("potrójne", "", "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);
zwróć $dekodowany_tekst; ) )
funkcja hexToStr($hex) (
$ciąg="";
dla ($i=0; $i< strlen($hex)-1; $i+=2) { $string .= chr(hexdec($hex[$i].$hex[$i+1])); }
zwróć $ciąg; )

$str = "Bułeczki, które należy zaszyfrować!
Według klucza";
$code = strToHex(__encode($str, "Mój#klucz-do-36-simvolov"));
echo "Zaszyfrowany kod: ".$code."
";

$str = __decode(hexToStr($code), "Mój#klucz-do-36-simvolov");
echo "Odszyfrowany kod: ".$str."
";
?>

Możesz szyfrować zawartość HTML. Długość klucza nie może przekraczać 36 znaków.

Tą metodą można zaszyfrować część danych i umieścić je w pliku txt lub bazie danych, a następnie odebrać je poprzez odszyfrowanie za pomocą klucza.

Oczywiście każdy kod można odszyfrować/zhakować i nie jest to wyjątkiem, dlatego używaj silnych metod szyfrowania.

Jedną z podstawowych prawd kryptografii jest to, że nie powinieneś niczego wymyślać w tej dziedzinie, chyba że jesteś profesjonalistą. Jest to po części prawda, ponieważ wszystko, co najlepsze, zostało już dawno wynalezione, wycierpione i stosowane od dziesięcioleci w dziedzinie technologii informatycznych. Druga strona prawdy jest taka, że ​​rozwój określonej dziedziny wiedzy następuje jedynie przy stałym dopływie do niej świeżych pomysłów i oryginalnych rozwiązań.

Z oczywistych powodów nie będziemy brać na cel gigantów kryptografii przemysłowej pokroju AES, ale zanurzymy się, że tak powiem, w swoje własne badania kryptograficzne z blackjackiem i radością.

Częściowo dlatego, że jest to ciekawe, częściowo dlatego, że modelując coś własnego i porównując to z uznanymi standardami, wyraźnie widać kontrast, skuteczne rozwiązania i wręcz zaniechania i rozumie się, do czego można dążyć, aby poprawić efektywność.

Ale dość już wody.

Załóżmy, że nasza aplikacja internetowa jest napisana w PHP, wymaga odwracalnego szyfrowania i wierzymy, że możemy napisać własny system szyfrowania.

Napiszmy więc własny, odwracalny system szyfrowania z kluczami prywatnymi i publicznymi, który będzie miał następujące cechy mniej lub bardziej bezpiecznego algorytmu kryptograficznego:

  1. Obecność symboli szumu w końcowym szyfrze.
  2. Informacje w każdym kanale nadawca-docelowy będą szyfrowane przy użyciu klucza prywatnego, a funkcja dopasowywania będzie unikalna dla każdego klucza.
  3. Każda wiadomość otrzyma kod skrótu – unikalny kod będący funkcją klucza prywatnego i oryginalnej wiadomości. Jest to wymagane, aby osiągnąć unikalność funkcji dopasowania „symbolu źródłowego”.<=>zakodowany symbol” nie tylko dla kanału „Nadawca-Odbiorca”, ale także dla każdej indywidualnej wiadomości.

    Zatem nawet jeśli wyobrazimy sobie, że zgodność zakodowanych i oryginalnych symboli dla konkretnej wiadomości została poznana dzięki zastosowaniu analizy kryptograficznej, na przykład analizy częstotliwości, nie daje to żadnych preferencji podczas badania innej wiadomości.

  4. Aby skomplikować analizę częstotliwości, zakodujemy każdy symbol wiadomości początkowej za pomocą dwóch symboli szyfrujących.
Więc co się stało.

Rzeczywiście, widać efekt końcowy

Klasa SymCoder obejmuje metody szyfrowania i deszyfrowania.

Szyfrowanie odbywa się metodą code(), która jako dane wejściowe przyjmuje oryginalną wiadomość.

Tutaj wiadomość z wygenerowanej tabeli korespondencji w tab_coded tworzy zaszyfrowaną wiadomość, rozcieńczoną wzdłuż krawędzi i wewnątrz symbolami szumu.

Nawiasem mówiąc, symbole szumu są unikalne dla każdego kanału docelowego nadawcy, ponieważ są generowane przy użyciu klucza kanału, ale nie są unikalne dla wiadomości. Symbole używane do szyfrowania w code_symbols to niektóre znaki interpunkcyjne i symbole, takie jak%, @ itp.

Na każdy zakodowany symbol przypadają dwa symbole z code_symbols, z oczywistych względów jest ich kilka razy mniej niż symboli zakodowanych.

Tabela korespondencji create_tab_coded jest budowana przy użyciu translacji skrótu klucza komunikatu na tablicę z liczbą elementów równą liczbie elementów w tablicy symboli kodu. Pozycja wyjściowa przy przechodzeniu przez kody dwuznakowe jest również zawsze inna i jest powiązana z kluczem kanału. Dzięki temu można mieć pewność, że algorytm przechodzenia przez zakodowane symbole i dopasowywania do nich symboli kodu będzie zawsze (lub gwarantuje, że często) będzie inny.

Na przykład wiadomość „Witaj, świecie” po zakodowaniu wygląda następująco:

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

A oto ta sama wiadomość, ponownie zakodowana:

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

Można zauważyć, że skrót tej samej wiadomości jest taki sam, ale szyfr się zmienia – symbole szumu są dodawane w dowolnym dopasowaniu i w dowolnej kolejności dla każdego nowego szyfrowania.

Wiadomości charakteryzują się redundancją, która maleje wraz ze wzrostem objętości wiadomości, aż do 10% szumu (w przypadku najkrótszych wiadomości szum sięga 90% lub więcej procent), minimalna długość zaszyfrowanej wiadomości to 116 znaków. Jedną z wad tej metody szyfrowania jest to, że zakodowane wiadomości są co najmniej podwojone.

Dekodowanie polega na odwrotnym tłumaczeniu postaci „symbolu kodu” – oryginalnego symbolu z wyciętym z komunikatu szumem. Co może być kluczem? Zasadniczo dowolny ciąg znaków, który jest unikalny dla każdej pary miejsce docelowe-odbiornik.

Na przykład, jeśli tworzysz komunikator z szyfrowaniem wiadomości, to najprostsza wersja klucza prywatnego może mieć postać md5($user_id_1. $salt. $user_id_2), wtedy klucz będzie unikalny dla każdego kanału wiadomości.

Załóżmy, że chcesz wymienić dane między dwoma serwerami. Aby chronić dane przed podsłuchiwaniem ruchu, są one szyfrowane. Cóż, na przykład przekazywanie działań w ramach botnetu. Zasadniczo nie jest to szyfrowanie, ale nazywa się to kodowaniem, a do dekodowania takiego kodu wykorzystywane są dobrze znane funkcje.

Jako kolejny przykład pseudoszyfrowania podam przykład „szyfrowania” haseł w bazie jednego CMS-a - tam hasła nie są szyfrowane w md5() lub , ale po prostu kodowane za pomocą base64. Te. W przypadku wycieku bazy danych hakerowi nie będzie trudno odszyfrować wszystkie hasła za pomocą wbudowanej funkcji PHP base64_decode().

Musimy przesyłać dane bez obawy, że ktoś będzie w stanie przechwycić tekst i go odszyfrować. PHP ma popularny pakiet do szyfrowania danych o nazwie Mcrypt, który zapewnia szyfrowanie dwukierunkowe (to znaczy faktyczne szyfrowanie i deszyfrowanie danych).

Wersja Mcrypt 2.4.7 obsługuje następujące algorytmy szyfrowania symetrycznego: 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 itp. Więcej szczegółów na temat każdego algorytmu można znaleźć w Wikipedii.

Ponieważ stosowane jest szyfrowanie symetryczne, klucz musi być znany obu stronom i utrzymywany w tajemnicy.

Przykład szyfrowania i deszyfrowania ciągu znaków

mcrypt_module_open("des", "", "ecb", "")
Ta funkcja otwiera moduł algorytmu i używany tryb. W tym przykładzie algorytm DES działa w trybie EBC.

$key = substr($key, 0, mcrypt_enc_get_key_size($td));
Maksymalny rozmiar klucza należy uzyskać wywołując funkcję mcrypt_enc_get_key_size(), a każda wartość mniejsza niż ta będzie poprawna.

$s = mcrypt_generic($td, $source);
Podczas szyfrowania dane są dopełniane zerowymi bajtami, aby zapewnić długość n*blocksize. Rozmiar bloku Rozmiar bloku jest określany przez algorytm (w przypadku DES rozmiar bloku wynosi 64 bity). Dlatego podczas deszyfrowania na końcu linii może pojawić się „\0”, które jest usuwane przez funkcję trim()