Jak zaszyfrować i odszyfrować Łańcuch PHP?
Chodzi mi o to, że:
Original String + Salt or Key --> Encrypted String
Encrypted String + Salt or Key --> Decrypted (Original String)
Może coś w stylu:
"hello world!" + "ABCD1234" --> Encrypt --> "2a2ffa8f13220befbe30819047e23b2c" (may be, for e.g)
"2a2ffa8f13220befbe30819047e23b2c" --> Decrypt with "ABCD1234" --> "hello world!"
- w PHP, jak możesz to zrobić?
Próba użycia Crypt_Blowfish
, Ale mi nie wyszło.
6 answers
Zanim zrobisz cokolwiek dalej, Postaraj się zrozumieć różnicę między szyfrowaniem a uwierzytelnianiem, i dlaczego prawdopodobnie chcesz uwierzytelnionego szyfrowania , a nie tylko szyfrowania .
Aby zaimplementować uwierzytelnione szyfrowanie, chcesz zaszyfrować MAC. kolejność szyfrowania i uwierzytelniania jest bardzo ważna! jedna z istniejących odpowiedzi na to pytanie popełniła ten błąd; podobnie jak wiele kryptografii biblioteki napisane w PHP.
Należy unikać implementacji własnej kryptografii[26], a zamiast tego korzystać z bezpiecznej biblioteki napisanej i recenzowanej przez ekspertów ds. kryptografii.Aktualizacja: PHP 7.2 dostarcza teraz libsodium ! Zaktualizowano PHP do wersji 7.2 lub wyższej i postępuj zgodnie z poradami libsodium w tej odpowiedzi.
Użyj libsodium, jeśli masz dostęp do PECL (lub sodium_compat jeśli chcesz libsodium bez PECL); inaczej...
użyj defuse / PHP-encryption; nie obracaj własnej kryptografii!
Obie biblioteki połączone powyżej ułatwiają i bezbolesne implementowanie uwierzytelnionego szyfrowania do własnych bibliotek.
Jeśli nadal chcesz napisać i wdrożyć własną bibliotekę kryptograficzną, wbrew konwencjonalnej mądrości każdego eksperta w dziedzinie kryptografii w Internecie, są to kroki, które musisz wykonać weź.
Szyfrowanie:
- Szyfruj za pomocą AES w trybie CTR. Możesz również użyć GCM (co eliminuje potrzebę oddzielnego komputera MAC). Dodatkowo, ChaCha20 i Salsa20 (dostarczone przez libsodium) są szyframi strumieniowymi i nie wymagają specjalnych trybów.
- jeśli nie wybrałeś GCM powyżej, powinieneś uwierzytelnić szyfrogram za pomocą HMAC-SHA-256(lub, w przypadku szyfrów strumieniowych, Poly1305-większość API libsodium robi to za Ciebie). MAC powinien pokrywać kroplówkę jak i szyfrogram!
Odszyfrowanie:
- jeśli nie użyto Poly1305 lub GCM, Przelicz ponownie MAC szyfrogramu i porównaj go z komputerem MAC, który został wysłany za pomocą
hash_equals()
. Jeśli zawiedzie, przerwij.
Odszyfruj wiadomość.
Inne Względy Projektowe:
- nigdy niczego nie Kompresuj. Zaszyfrowany tekst nie jest kompresowalny; kompresowanie tekstu jawnego przed szyfrowaniem może prowadzić do wycieków informacji (np. przestępstwa i naruszenia na TLS).
- upewnij się, że używasz
mb_strlen()
imb_substr()
, używając trybu zestawu znaków'8bit'
, aby zapobiec problemommbstring.func_overload
. - IVs powinny być generowane za pomocą CSPRNG ; jeśli używasz
mcrypt_create_iv()
, nie stosowaćMCRYPT_RAND
!- sprawdź również random_compat.
- chyba że używasz konstrukcji AEAD, zawsze Szyfruj potem MAC!
-
bin2hex()
,base64_encode()
, itd. może wyciekać informacje o kluczach szyfrowania za pośrednictwem czas pamięci podręcznej. Unikaj ich, jeśli to możliwe.
Nawet jeśli zastosujesz się do podanych tu rad, wiele może pójść nie tak z kryptografią. Zawsze miej eksperta w dziedzinie kryptografii.Jeśli nie masz szczęścia, aby zaprzyjaźnić się ze studentem kryptografii na lokalnym Uniwersytecie, zawsze możesz skorzystać z forum wymiany stosów kryptograficznych (Cryptography Stack Exchange).
Jeśli potrzebujesz profesjonalnej analizy realizacji, zawsze możesz wynająć renomowany zespół konsultantów ds. bezpieczeństwa do przeglądu Twojego kodu kryptograficznego PHP (ujawnienie: mój pracodawca).Ważne: kiedy nie używać szyfrowania
Nie Szyfruj haseł. Zamiast tego chcesz hashować, używając jednego z tych algorytmów hashowania haseł:
Nigdy nie używaj funkcji skrótu ogólnego przeznaczenia (MD5, SHA256) do przechowywania haseł.
Nie Szyfruj parametrów URL . to złe narzędzie do pracy.
Przykład szyfrowania łańcuchów PHP z Libsodium
Jeśli korzystasz z PHP sodium_compat, aby osiągnąć ten sam wynik (choć wolniejszy).
<?php
declare(strict_types=1);
/**
* Encrypt a message
*
* @param string $message - message to encrypt
* @param string $key - encryption key
* @return string
* @throws RangeException
*/
function safeEncrypt(string $message, string $key): string
{
if (mb_strlen($key, '8bit') !== SODIUM_CRYPTO_SECRETBOX_KEYBYTES) {
throw new RangeException('Key is not the correct size (must be 32 bytes).');
}
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$cipher = base64_encode(
$nonce.
sodium_crypto_secretbox(
$message,
$nonce,
$key
)
);
sodium_memzero($message);
sodium_memzero($key);
return $cipher;
}
/**
* Decrypt a message
*
* @param string $encrypted - message encrypted with safeEncrypt()
* @param string $key - encryption key
* @return string
* @throws Exception
*/
function safeDecrypt(string $encrypted, string $key): string
{
$decoded = base64_decode($encrypted);
$nonce = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
$ciphertext = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');
$plain = sodium_crypto_secretbox_open(
$ciphertext,
$nonce,
$key
);
if (!is_string($plain)) {
throw new Exception('Invalid MAC');
}
sodium_memzero($ciphertext);
sodium_memzero($key);
return $plain;
}
Następnie przetestować go out:
<?php
// This refers to the previous code block.
require "safeCrypto.php";
// Do this once then store it somehow:
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
$message = 'We are all living in a yellow submarine';
$ciphertext = safeEncrypt($message, $key);
$plaintext = safeDecrypt($ciphertext, $key);
var_dump($ciphertext);
var_dump($plaintext);
Halit-Libsodium Łatwiejsze
Jednym z projektów, nad którymi pracowałem, jest biblioteka szyfrująca o nazwie Halite , która ma na celu uczynienie libsodium łatwiejszym i bardziej intuicyjnym.
<?php
use \ParagonIE\Halite\KeyFactory;
use \ParagonIE\Halite\Symmetric\Crypto as SymmetricCrypto;
// Generate a new random symmetric-key encryption key. You're going to want to store this:
$key = new KeyFactory::generateEncryptionKey();
// To save your encryption key:
KeyFactory::save($key, '/path/to/secret.key');
// To load it again:
$loadedkey = KeyFactory::loadEncryptionKey('/path/to/secret.key');
$message = 'We are all living in a yellow submarine';
$ciphertext = SymmetricCrypto::encrypt($message, $key);
$plaintext = SymmetricCrypto::decrypt($ciphertext, $key);
var_dump($ciphertext);
var_dump($plaintext);
Całą podstawową kryptografią zajmuje się libsodium.
Przykład z defuse / PHP-encryption
<?php
/**
* This requires https://github.com/defuse/php-encryption
* php composer.phar require defuse/php-encryption
*/
use Defuse\Crypto\Crypto;
use Defuse\Crypto\Key;
require "vendor/autoload.php";
// Do this once then store it somehow:
$key = Key::createNewRandomKey();
$message = 'We are all living in a yellow submarine';
$ciphertext = Crypto::encrypt($message, $key);
$plaintext = Crypto::decrypt($ciphertext, $key);
var_dump($ciphertext);
var_dump($plaintext);
Uwaga: Crypto::encrypt()
zwraca kodowane szesnastkowo wyjście.
Zarządzanie Kluczami Szyfrowania
Jeśli skusisz się na Użyj "hasła", przestań natychmiast. Potrzebujesz losowego 128-bitowego klucza szyfrującego, a nie ludzkiego pamiętnego hasła.
Możesz przechowywać klucz szyfrujący do długotrwałego użytkowania w następujący sposób:]}$storeMe = bin2hex($key);
I na żądanie możesz go pobrać w następujący sposób:
$key = hex2bin($storeMe);
I zdecydowanie zalecam po prostu przechowywanie losowo wygenerowanego klucza do długotrwałego użycia zamiast jakiegokolwiek hasła jako klucza (lub do uzyskania klucza).
Jeśli używasz Defuse ' s biblioteka:
"ale ja naprawdę chcę użyć hasła."
To zły pomysł, ale oto jak to zrobić bezpiecznie.Najpierw Wygeneruj losowy klucz i zachowaj go w stałej.
/**
* Replace this with your own salt!
* Use bin2hex() then add \x before every 2 hex characters, like so:
*/
define('MY_PBKDF2_SALT', "\x2d\xb7\x68\x1a\x28\x15\xbe\x06\x33\xa0\x7e\x0e\x8f\x79\xd5\xdf");
Zauważ, że dodajesz dodatkową pracę i możesz użyć tej stałej jako klucza i zaoszczędzić sobie wiele bólu serca!
Następnie użyj PBKDF2 (w ten sposób), aby uzyskać odpowiedni klucz szyfrowania z hasła zamiast szyfrowania hasłem bezpośrednio.
/**
* Get an AES key from a static password and a secret salt
*
* @param string $password Your weak password here
* @param int $keysize Number of bytes in encryption key
*/
function getKeyFromPassword($password, $keysize = 16)
{
return hash_pbkdf2(
'sha256',
$password,
MY_PBKDF2_SALT,
100000, // Number of iterations
$keysize,
true
);
}
Nie używaj tylko 16-znakowego hasła. Twój klucz szyfrowania zostanie komicznie złamany.
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-07-24 12:11:36
Czego nie robić
Mam to na sobie. Właściwie znalazłem jakąś odpowiedź w google i coś zmodyfikowałem. wynik jest całkowicie niepewny jednak.WARNING:
Ta odpowiedź używa EBC . EBC nie jest trybem szyfrowania, to tylko budulec. Użycie ECB, jak pokazano w tej odpowiedzi, nie zaszyfruje łańcucha znaków w sposób bezpieczny. Nie używaj EBC w swoim kodzie. Zobacz odpowiedź Scotta dla dobrego rozwiązania.
<?php
define("ENCRYPTION_KEY", "!@#$%^&*");
$string = "This is the original data string!";
echo $encrypted = encrypt($string, ENCRYPTION_KEY);
echo "<br />";
echo $decrypted = decrypt($encrypted, ENCRYPTION_KEY);
/**
* Returns an encrypted & utf8-encoded
*/
function encrypt($pure_string, $encryption_key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted_string = mcrypt_encrypt(MCRYPT_BLOWFISH, $encryption_key, utf8_encode($pure_string), MCRYPT_MODE_ECB, $iv);
return $encrypted_string;
}
/**
* Returns decrypted original string
*/
function decrypt($encrypted_string, $encryption_key) {
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$decrypted_string = mcrypt_decrypt(MCRYPT_BLOWFISH, $encryption_key, $encrypted_string, MCRYPT_MODE_ECB, $iv);
return $decrypted_string;
}
?>
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 22:12:32
Jestem spóźniony na imprezę, ale szukając właściwego sposobu, aby to zrobić, natknąłem się na tę stronę był to jeden z najlepszych wyników wyszukiwania Google, więc chciałbym podzielić się moim zdaniem na temat problemu, który uważam za aktualny w momencie pisania tego postu(początek 2017). Od PHP 7.1.0 mcrypt_decrypt
i mcrypt_encrypt
będą przestarzałe, więc budowanie przyszłościowego kodu powinno używać openssl_encrypt i openssl_decrypt
Możesz zrobić coś takiego:
$string_to_encrypt="Test";
$password="password";
$encrypted_string=openssl_encrypt($string_to_encrypt,"AES-128-ECB",$password);
$decrypted_string=openssl_decrypt($encrypted_string,"AES-128-ECB",$password);
Ważne : używa trybu EBC , który nie jest bezpieczny. Jeśli potrzebujesz prostego rozwiązania bez konieczności brania udziału w awaryjnym kursie inżynierii kryptograficznej, nie pisz go sam, po prostu użyj biblioteki.
Możesz również użyć innych metod rozdrabniania, w zależności od potrzeb bezpieczeństwa. Aby zapoznać się z dostępnymi metodami chipper, zajrzyj do funkcji openssl_get_cipher_methods .
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-04-11 20:42:57
For Laravel framework
Jeśli używasz Laravel framework, łatwiej jest zaszyfrować i odszyfrować za pomocą wewnętrznych funkcji.
$string = 'Some text to be encrypted';
$encrypted = \Illuminate\Support\Facades\Crypt::encrypt($string);
$decrypted_string = \Illuminate\Support\Facades\Crypt::decrypt($encrypted);
var_dump($string);
var_dump($encrypted);
var_dump($decrypted_string);
Uwaga: Pamiętaj, aby ustawić losowy ciąg znaków 16, 24 lub 32 w kluczowa Opcja konfiguracji / aplikacji.plik php. W przeciwnym razie zaszyfrowane wartości nie będzie bezpieczny.
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-12-14 12:58:54
Notatka historyczna: to zostało napisane w czasie PHP4. To się teraz nazywa "legacy code".
Zostawiłam tę odpowiedź dla celów historycznych - ale niektóre metody są obecnie przestarzałe, metoda szyfrowania DES nie jest zalecaną praktyką itp.
Nie zaktualizowałem tego kodu z dwóch powodów: 1) nie pracuję już ręcznie z metodami szyfrowania w PHP i 2) ten kod nadal służy celowi, do którego był przeznaczony: zademonstrować minimum, uproszczona koncepcja działania szyfrowania w PHP.
Jeśli znajdziesz podobnie uproszczone," szyfrowanie PHP dla manekinów " źródło, które może uruchomić ludzi w 10-20 linijek kodu lub mniej, daj mi znać w komentarzach.
Poza tym, ciesz się klasycznym odcinkiem wczesnej ery minimalistycznego szyfrowania odpowiedzi PHP4.
Najlepiej mieć-lub można uzyskać-dostęp do biblioteki PHP mcrypt, jako jej z pewnością popularne i bardzo przydatne różnych zadań. Oto bieg poniżej różne rodzaje szyfrowania i przykładowy kod: techniki szyfrowania w PHP
//Listing 3: Encrypting Data Using the mcrypt_ecb Function
<?php
echo("<h3> Symmetric Encryption </h3>");
$key_value = "KEYVALUE";
$plain_text = "PLAINTEXT";
$encrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $plain_text, MCRYPT_ENCRYPT);
echo ("<p><b> Text after encryption : </b>");
echo ( $encrypted_text );
$decrypted_text = mcrypt_ecb(MCRYPT_DES, $key_value, $encrypted_text, MCRYPT_DECRYPT);
echo ("<p><b> Text after decryption : </b>");
echo ( $decrypted_text );
?>
Kilka ostrzeżeń:
1) Nigdy nie używaj odwracalnego lub "symetrycznego" szyfrowania, gdy wystarczy jednokierunkowy hash.
2) Jeśli dane są naprawdę wrażliwe, takie jak numery kart kredytowych lub ubezpieczeń społecznych, przestań; Potrzebujesz więcej niż jakikolwiek prosty fragment kodu, ale raczej potrzebujesz zaprojektowanej do tego celu biblioteki kryptograficznej i znacznej ilości czasu na badania metody niezbędne. Co więcej, kryptografia oprogramowania jest prawdopodobnie
3) każdy rodzaj łatwego do wdrożenia szyfrowania, jak wymieniono tutaj, może w rozsądny sposób chronić delikatnie ważne informacje, które chcesz zachować przed wścibstwem oczu lub ograniczyć narażenie w przypadku przypadkowego / zamierzonego wycieku. Ale ponieważ klucz jest przechowywany w postaci zwykłego tekstu na serwerze WWW, jeśli mogą uzyskać dane, mogą uzyskać klucz deszyfrujący.
Niech tak będzie, baw się dobrze:)
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 22:12:01
Jeśli nie chcesz używać biblioteki (którą powinieneś), użyj czegoś takiego (PHP 7):
function sign($message, $key) {
return hash_hmac('sha256', $message, $key) . $message;
}
function verify($bundle, $key) {
return hash_equals(
hash_hmac('sha256', mb_substr($bundle, 64, null, '8bit'), $key),
mb_substr($bundle, 0, 64, '8bit')
);
}
function getKey($password, $keysize = 16) {
return hash_pbkdf2('sha256',$password,'some_token',100000,$keysize,true);
}
function encrypt($message, $password) {
$iv = random_bytes(16);
$key = getKey($password);
$result = sign(openssl_encrypt($message,'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv), $key);
return bin2hex($iv).bin2hex($result);
}
function decrypt($hash, $password) {
$iv = hex2bin(substr($hash, 0, 32));
$data = hex2bin(substr($hash, 32));
$key = getKey($password);
if (!verify($data, $key)) {
return null;
}
return openssl_decrypt(mb_substr($data, 64, null, '8bit'),'aes-256-ctr',$key,OPENSSL_RAW_DATA,$iv);
}
$string_to_encrypt='John Smith';
$password='password';
$encrypted_string=encrypt($string_to_encrypt, $password);
$decrypted_string=decrypt($encrypted_string, $password);
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-05-16 15:27:21