Jak szyfrować / odszyfrować dane w php?

Obecnie jestem studentem i studiuję PHP, staram się zrobić proste szyfrowanie / deszyfrowanie danych w PHP. Zrobiłem trochę badań online i niektóre z nich były dość mylące(przynajmniej dla mnie).

Oto co próbuję zrobić:

Mam tabelę składającą się z tych pól (UserID, Fname, Lname, Email,Password)

Chcę mieć wszystkie pola zaszyfrowane, a następnie odszyfrowane(czy możliwe jest użycie sha256 do szyfrowania / deszyfrowania, jeśli nie jakiekolwiek algorytm szyfrowania)

Kolejną rzeczą, której chcę się nauczyć, jest to, jak stworzyć jeden sposób hash(sha256) w połączeniu z dobrą "solą". (W zasadzie chcę tylko mieć prostą implementację szyfrowania / deszyfrowania, hash(sha256)+salt) Proszę pana, Pańskie odpowiedzi będą bardzo pomocne i będą bardzo mile widziane. Thank you++

Author: Scott Arciszewski, 2012-06-06

6 answers

Przedmowa

Zaczynając od definicji tabeli:

- UserID
- Fname
- Lname
- Email
- Password
- IV

Oto zmiany:

  1. pola Fname, Lname i Email będą szyfrowane za pomocą szyfru symetrycznego, dostarczonego przez OpenSSL ,
  2. pole IV będzie przechowywać wektor inicjalizacji używany do szyfrowania. Wymagania dotyczące pamięci zależą od zastosowanego szyfru i trybu; więcej o tym później.
  3. pole Password zostanie zahaszowane za pomocą jednokierunkowej hash hasła,

Szyfrowanie

Szyfr i tryb

Wybór najlepszego szyfru i trybu szyfrowania jest poza zakresem tej odpowiedzi, ale ostateczny wybór wpływa na rozmiar zarówno klucza szyfrowania, jak i wektora inicjalizacji; w tym poście będziemy używać AES-256-CBC, który ma stały rozmiar bloku 16 bajtów i rozmiar klucza 16, 24 lub 32 bajtów.

Klucz szyfrujący

Dobry klucz szyfrujący to binarny blob to jest generowane z niezawodnego generatora liczb losowych. Zaleca się następujący przykład (>=5.3):

$key_size = 32; // 256 bits
$encryption_key = openssl_random_pseudo_bytes($key_size, $strong);
// $strong will be true if the key is crypto safe

Można to zrobić raz lub wiele razy (jeśli chcesz utworzyć łańcuch kluczy szyfrujących). Trzymaj to tak prywatnie, jak to tylko możliwe.

IV

Wektor inicjalizacji dodaje losowość do szyfrowania i jest wymagany dla trybu CBC. Wartości te powinny być idealnie użyte tylko raz( technicznie raz na klucz szyfrowania), więc aktualizacja do dowolnej części rząd powinien go regenerować.

Dostępna jest funkcja, która pomoże Ci wygenerować IV:

$iv_size = 16; // 128 bits
$iv = openssl_random_pseudo_bytes($iv_size, $strong);

Przykład

Zaszyfrujmy pole nazwa, używając wcześniejszych $encryption_key i $iv; aby to zrobić, musimy umieścić nasze dane do rozmiaru bloku:

function pkcs7_pad($data, $size)
{
    $length = $size - strlen($data) % $size;
    return $data . str_repeat(chr($length), $length);
}

$name = 'Jack';
$enc_name = openssl_encrypt(
    pkcs7_pad($name, 16), // padded data
    'AES-256-CBC',        // cipher and mode
    $encryption_key,      // secret key
    0,                    // options (not used)
    $iv                   // initialisation vector
);

Wymagania dotyczące przechowywania

Zaszyfrowane wyjście, podobnie jak IV, jest binarne; przechowywanie tych wartości w bazie danych może być wykonane za pomocą wyznaczonych typów kolumn, takich jak BINARY lub VARBINARY.

Wyjście wartość, podobnie jak IV, jest binarna. aby zapisać te wartości w MySQL, rozważ użycie BINARY lub VARBINARY kolumny. Jeśli nie jest to opcja, można również przekonwertować dane binarne na reprezentację tekstową za pomocą base64_encode() lub bin2hex(), wymaga to od 33% do 100% więcej miejsca na dysku.

Deszyfrowanie

Odszyfrowywanie przechowywanych wartości jest podobne:

function pkcs7_unpad($data)
{
    return substr($data, 0, -ord($data[strlen($data) - 1]));
}

$row = $result->fetch(PDO::FETCH_ASSOC); // read from database result
// $enc_name = base64_decode($row['Name']);
// $enc_name = hex2bin($row['Name']);
$enc_name = $row['Name'];
// $iv = base64_decode($row['IV']);
// $iv = hex2bin($row['IV']);
$iv = $row['IV'];

$name = pkcs7_unpad(openssl_decrypt(
    $enc_name,
    'AES-256-CBC',
    $encryption_key,
    0,
    $iv
));

Uwierzytelnione szyfrowanie

Możesz jeszcze bardziej poprawić integralność wygenerowany zaszyfrowany tekst poprzez dołączenie podpisu wygenerowanego z tajnego klucza (innego niż klucz szyfrowania) i zaszyfrowanego tekstu. Zanim zaszyfrowany tekst zostanie odszyfrowany, podpis jest najpierw sprawdzany(najlepiej metodą porównywania w czasie stałym).

Przykład

// generate once, keep safe
$auth_key = openssl_random_pseudo_bytes(32, $strong);

// authentication
$auth = hash_hmac('sha256', $enc_name, $auth_key, true);
$auth_enc_name = $auth . $enc_name;

// verification
$auth = substr($auth_enc_name, 0, 32);
$enc_name = substr($auth_enc_name, 32);
$actual_auth = hash_hmac('sha256', $enc_name, $auth_key, true);

if (hash_equals($auth, $actual_auth)) {
    // perform decryption
}

Zobacz: hash_equals()

Hashowanie

Przechowywanie hasła odwracalnego w bazie danych musi być unikane w jak największym stopniu; chcesz tylko zweryfikować hasło, a nie znając jego zawartość. Jeśli użytkownik straci swoje hasło, lepiej pozwolić mu je zresetować, niż wysłać mu swoje oryginalne (upewnij się, że Resetowanie hasła może być wykonane tylko przez ograniczony czas).

Stosowanie funkcji hash jest operacją jednokierunkową; następnie można ją bezpiecznie wykorzystać do weryfikacji bez ujawniania oryginalnych danych; w przypadku haseł metoda brute force jest wykonalnym podejściem do odkrycia jej ze względu na stosunkowo krótką długość i słabe wybory haseł wielu osób.

Algorytmy haszujące, takie jak MD5 lub SHA1, zostały stworzone w celu weryfikacji zawartości pliku pod znaną wartością haszu. Są one znacznie zoptymalizowane, aby ta weryfikacja była tak szybka, jak to możliwe, a jednocześnie dokładna. Ze względu na stosunkowo ograniczoną przestrzeń wyjściową łatwo było zbudować bazę danych ze znanymi hashami i ich odpowiednimi hashami, tabelami tęczowymi.

Dodanie soli do hasła przed hashowaniem uczyniłoby tęczową tabelę bezużyteczną, ale najnowszy sprzęt postępy sprawiły, że poszukiwania brute force stały się realnym podejściem. Dlatego potrzebujesz algorytmu haszującego, który jest celowo powolny i po prostu niemożliwy do zoptymalizowania. Powinien również być w stanie zwiększyć obciążenie szybszego sprzętu bez wpływu na możliwość weryfikacji istniejących hashów haseł, aby było to przyszłościowe.

Obecnie dostępne są dwa popularne opcje:

  1. PBKDF2 (Password Based Key Derivation Function v2)
  2. bcrypt (aka Blowfish)

Ta odpowiedź użyje przykładu z bcrypt.

Pokolenie

Hash hasła można wygenerować w następujący sposób:

$password = 'my password';
$random = openssl_random_pseudo_bytes(18);
$salt = sprintf('$2y$%02d$%s',
    13, // 2^n cost factor
    substr(strtr(base64_encode($random), '+', '.'), 0, 22)
);

$hash = crypt($password, $salt);

Sól powstaje z openssl_random_pseudo_bytes() aby utworzyć losowy blob danych, które są następnie uruchamiane przez base64_encode() i strtr(), aby dopasować wymagany alfabet [A-Za-z0-9/.].

The crypt() funkcja wykonuje hashowanie w oparciu o algorytm ($2y$ Dla Blowfish), współczynnik kosztu (współczynnik 13 trwa około 0,40 s na maszynie 3GHz) i sól 22 znaków.

Walidacja

Po pobraniu wiersza zawierającego informacje o użytkowniku, walidujesz hasło w ten sposób:

$given_password = $_POST['password']; // the submitted password
$db_hash = $row['Password']; // field with the password hash

$given_hash = crypt($given_password, $db_hash);

if (isEqual($given_hash, $db_hash)) {
    // user password verified
}

// constant time string compare
function isEqual($str1, $str2)
{
    $n1 = strlen($str1);
    if (strlen($str2) != $n1) {
        return false;
    }
    for ($i = 0, $diff = 0; $i != $n1; ++$i) {
        $diff |= ord($str1[$i]) ^ ord($str2[$i]);
    }
    return !$diff;
}

Aby zweryfikować hasło, wywołujesz crypt() ponownie, ale przekazujesz wcześniej obliczony hash jako wartość salt. Zwracana wartość daje ten sam hash, jeśli podane hasło jest zgodne z Hashem. Aby zweryfikować hash, często zaleca się stosowanie stałego czasu funkcja porównywania, aby uniknąć ataków czasowych.

Hashowanie haseł za pomocą PHP 5.5

PHP 5.5 wprowadził funkcje hashowania haseł , których można użyć do uproszczenia powyższej metody hashowania:

$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 13]);

I sprawdzanie:

if (password_verify($given_password, $db_hash)) {
    // password valid
}

Zobacz: password_hash(), password_verify()

 271
Author: Ja͢ck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-11 10:44:57

Myślę, że już wcześniej na to odpowiadano...ale w każdym razie, jeśli chcesz zaszyfrować/odszyfrować dane, nie możesz użyć SHA256

//Key
$key = 'SuperSecretKey';

//To Encrypt:
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, 'I want to encrypt this', MCRYPT_MODE_ECB);

//To Decrypt:
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_ECB);
 20
Author: romo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-06 14:37:22

Odpowiedz tło i Wyjaśnienie

Aby zrozumieć to pytanie, musisz najpierw zrozumieć, czym jest SHA256. SHA256 jest kryptograficzną funkcją skrótu . Kryptograficzna funkcja skrótu jest funkcją jednokierunkową, której wyjście jest kryptograficznie bezpieczne. Oznacza to, że łatwo jest obliczyć hash (odpowiednik szyfrowania danych), ale trudno uzyskać oryginalne dane wejściowe za pomocą hash (odpowiednik deszyfrowania danych). Ponieważ użycie kryptograficznej funkcji skrótu oznacza odszyfrowanie obliczeniowo niewykonalne, więc nie można wykonać deszyfrowania za pomocą SHA256.

To, czego chcesz użyć, to funkcja dwukierunkowa, ale dokładniej, szyfr blokowy . Funkcja umożliwiająca zarówno szyfrowanie, jak i deszyfrowanie danych. Funkcje mcrypt_encrypt i mcrypt_decrypt domyślnie używają algorytmu Blowfish. PHP używa mcrypt można znaleźć w tym podręczniku. Istnieje również lista definicji szyfrów do wyboru szyfru, którego używa mcrypt. Wiki o Blowfish można znaleźć na Wikipedia. Szyfr blokowy szyfruje dane wejściowe w blokach o znanej wielkości i pozycji za pomocą znanego klucza, dzięki czemu dane mogą być później odszyfrowane za pomocą klucza. To jest to, czego SHA256 nie może Ci zapewnić.

Kod

$key = 'ThisIsTheCipherKey';

$ciphertext = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, 'This is plaintext.', MCRYPT_MODE_CFB);

$plaintext = mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $encrypted, MCRYPT_MODE_CFB);
 14
Author: cytinus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-06 12:15:51

Oto przykład użycia openssl_encrypt

//Encryption:
$textToEncrypt = "My Text to Encrypt";
$encryptionMethod = "AES-256-CBC";
$secretHash = "encryptionhash";
$iv = mcrypt_create_iv(16, MCRYPT_RAND);
$encryptedText = openssl_encrypt($textToEncrypt,$encryptionMethod,$secretHash, 0, $iv);

//Decryption:
$decryptedText = openssl_decrypt($encryptedText, $encryptionMethod, $secretHash, 0, $iv);
print "My Decrypted Text: ". $decryptedText;
 7
Author: Vivek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-19 20:28:31

Zajęło mi sporo czasu, aby dowiedzieć się, jak nie uzyskać false podczas korzystania z openssl_decrypt() i uzyskać szyfrowanie i deszyfrowanie działa.

    // cryptographic key of a binary string 16 bytes long (because AES-128 has a key size of 16 bytes)
    $encryption_key = '58adf8c78efef9570c447295008e2e6e'; // example
    $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
    $encrypted = openssl_encrypt($plaintext, 'aes-256-cbc', $encryption_key, OPENSSL_RAW_DATA, $iv);
    $encrypted = $encrypted . ':' . base64_encode($iv);

    // decrypt to get again $plaintext
    $parts = explode(':', $encrypted);
    $decrypted = openssl_decrypt($parts[0], 'aes-256-cbc', $encryption_key, OPENSSL_RAW_DATA, base64_decode($parts[1])); 

Jeśli chcesz przekazać zaszyfrowany ciąg poprzez URL, musisz urlencode ciąg:

    $encrypted = urlencode($encrypted);

Aby lepiej zrozumieć, co się dzieje, przeczytaj:

Do wygenerowania 16 bajtowych kluczy możesz użyć:

    $bytes = openssl_random_pseudo_bytes(16);
    $hex = bin2hex($bytes);

Aby zobaczyć komunikaty o błędach OpenSSL możesz użyć: echo openssl_error_string();

Mam nadzieję, że to pomoże.
 0
Author: Kai Noack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-08 21:26:30
     function my_simple_crypt( $string, $action = 'e' ) {
        // you may change these values to your own
        $secret_key = 'my_simple_secret_key';
        $secret_iv = 'my_simple_secret_iv';

        $output = false;
        $encrypt_method = "AES-256-CBC";
        $key = hash( 'sha256', $secret_key );
        $iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );

        if( $action == 'e' ) {
            $output = base64_encode( openssl_encrypt( $string, $encrypt_method, $key, 0, $iv ) );
        }
        else if( $action == 'd' ){
            $output = openssl_decrypt( base64_decode( $string ), $encrypt_method, $key, 0, $iv );
        }

        return $output;
    }
 0
Author: gaurav daxini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-20 07:12:05