PHP шифрование данных
Симметричное шифрование – это алгоритм шифрования, в котором используется один и тот же криптографический ключ как для шифрования, так и для расшифровки данных. Рассмотрим на PHP шифрование данных симметричным методом на основе алгоритма AES (Advanced Encryption Standard) – симметричного алгоритма блочного шифрования (размер блока 128 бит, ключ 128/192/256 бит). AES является одним из самых распространённых алгоритмов симметричного шифрования..
PHP шифрование данных AES
Как уже говорилось ранее, для шифровки и расшифровки потребуется ключ шифрования. Это может быть любая строка, но мы для его получения воспользуемся функцией, которая генерирует строку псевдослучайных байт длиной 40, и преобразуем полученный результат в шестнадцатеричное представление:
$bytes = openssl_random_pseudo_bytes(40); $hex = bin2hex($bytes); var_dump($hex);
На экран будет выведен результат следующего вида:
string(80) "5aa3c281e42ba7101f7227a7519d5e961c7bcf2b10a42914304bffc1afcebb1d2be98f53caa80d05"
Полученное значение мы будем использовать как секретный ключ шифрования и дешифрования данных (он должен храниться в тайне). Запишем его в переменную $key:
$key = "5aa3c281e42ba7101f7227a7519d5e961c7bcf2b10a42914304bffc1afcebb1d2be98f53caa80d05";
Теперь определим, что мы будем кодировать. Для первого примера возьмем обычную строку:
$data = 'Это строка закодирована симметричным алгоритмом шифрованием AES';
Мы будем шифровать данные алгоритмом AES с 192 битным ключом:
Все доступные методы шифрования можно посмотреть следующим образом:
var_dump(openssl_get_cipher_methods());
Имея данные для шифрования $data, выбранный метод $method и секретный ключ $key в PHP симметричное шифрование данных мы можем осуществить с помощью функции openssl_encrypt:
$encrypted = openssl_encrypt($data, $method, $key);
Выведем на экран результат с помощью var_dump($encrypted):
string(152) "qNiTUkY5GY63q2IjbZ034myIFAf7hyTX+dRJF4YjJmJCk15YqAccIigpECKlCmLEgft7WNUV3/yZVcSqxLO3aDDOoV/5oglU1hFRiLD9yBF9q6HrM0Ic2e0RCgXxaHFa6ae6dZ2mVzgSkZvZnasTYg= (opens in a new tab)" rel="noreferrer noopener" href="https://www.php.net/manual/ru/function.openssl-decrypt.php" target="_blank">openssl_decrypt: $decrypted = openssl_decrypt($encrypted, $method, $key);
Опять воспользуемся var_dump($decrypted):
string(107) "Это строка была закодирована симметричным шифрованием AES"
Конечный листинг примера симметричного шифрования/расшифровки данных на PHP будет следующий:
PHP шифрование файлов AES
В PHP шифрование файлов от шифрования данных отличается лишь тем, что содержимое файла сначала необходимо прочитать, проделать с ним необходимые операции, а затем – записать.
Создадим обычный текстовый файл в текущей директории:
$ echo 'Этот файл кодирован на PHP с помощью симметричного алгоритма AES' > aes.txt
Ключ и метод шифрования мы возьмем из предыдущего примера, а данные для кодирования получим из файла aes.txt с помощью функции file_get_contents:
$key = "5aa3c281e42ba7101f7227a7519d5e961c7bcf2b10a42914304bffc1afcebb1d2be98f53caa80d05"; $method = "AES-192-CBC"; $file = 'aes.txt'; $contents = file_get_contents($file);
Закодируем содержимое файла и запишем его в новый файл aes-encrypted.txt с помощью функции file_put_contents:
$contetsEncrypted = openssl_encrypt($contents, $method, $key); $fileEncrypted = 'aes-encrypted.txt'; file_put_contents($fileEncrypted, $contetsEncrypted);
Посмотрим содержимое полученного файла:
$ cat aes-encrypted.txt u1IdVyyNwECahzAaN0DQdSPx4lDiXHKXWc8/yl6KLne3tcyT/vUD/96Z84wgZHyhWc0daYT7JxiShat9xUjdQEC5V2nLuuMZ1/yUmIsE4HKZcvZEki99e0gAdtP9M0vdo82rEUfFnKe78wT7/zeOs1PBLaQvpXWbM8VcVeEVzTc=
Осталось попробовать расшифровать этот файл и записать его:
$contents = file_get_contents($fileEncrypted); $contentsDecrypted = openssl_decrypt($contents, $method, $key); $fileDecrypted = 'aes-decrypted.txt'; file_put_contents($fileDecrypted, $contentsDecrypted);
$ cat aes-decrypted.txt Этот файл кодирован на PHP с помощью симметричного алгоритма AES
Конечный листинг симметричного шифрования файла на PHP алгоритмом AES:
Асимметричное шифрование
Асимметричное шифрование отличается от симметричного тем, что для шифровки и расшифровки данных используется не один общий ключ, а два разных. Одним из самых распространенных алгоритмов асимметричного шифрования является RSA (аббревиатура от фамилий Rivest, Shamir и Adleman) — криптографический алгоритм с открытым ключом. В этом алгоритме для шифрования данных используется публичный ключ, а для расшифровки – секретный приватный ключ.
PHP шифрование данных RSA
Для работы с данным алгоритмом нам понадобятся публичный public.crt и приватный private.pem ключ. Получить их можно из консоли с помощью openssl. Сгенерируем пару rsa с ключом 2048 бит на 365 дней (“/C=RU/ST=MO/L=MOSCOW/O=POCKETADMIN/TECH=XX/CN=pocketadmin.tech/emailAddress=”example@pocketadmin.tech – информация о субъекте, который выпустил ключ):
$ openssl req -newkey rsa:2048 -nodes -keyout private.pem -out public.crt -x509 -days 365 -subj "/C=RU/ST=MO/L=MOSCOW/O=POCKETADMIN/TECH=XX/CN=pocketadmin.tech/emailAddress wp-block-code">$data = 'Эта строка была зашифрована на PHP асимметричным алгоритмом RSA'; $filePublicKey = 'public.crt'; $filePrivateKey = 'private.pem';
Ещё раз хочу обратить внимание, что сам приватный ключ необходимо хранить в тайне! Непосредственно для шифрования третьим лицам достаточно передать только публичный ключ.
Получаем содержимое файла с публичным ключом и извлекаем сам ключ:
$contentsPublicKey = file_get_contents($filePublicKey); $publicKey = openssl_get_publickey($contentsPublicKey);
С помощью функции openssl_public_encrypt шифруем данные $data публичным ключом $publicKey. Результат шифрования будет помещен в переменную $encrypted:
openssl_public_encrypt($data, $encrypted, $publicKey);
В дальнейшем, для расшифровки нам понадобится приватный ключ:
$contentsPrivateKey = file_get_contents($filePrivateKey); $privateKey = openssl_get_privatekey($contentsPrivateKey);
Чтобы расшифровать данные $encrypted приватным ключом $privateKey воспользуемся функцией openssl_private_decrypt. Результат помещается в переменную $decrypted:
openssl_private_decrypt($encrypted, $decrypted, $privateKey);
Проверим результат с помощью var_dump($decrypted):
string(112) "Эта строка была зашифрована на PHP асимметричным алгоритмом RSA"
Приведем весь код на PHP шифрования данных алгоритмом RSA:
PHP шифрование файлов RSA
Создадим простой текстовый файл, который мы будем шифровать:
$ echo 'Этот файл был зашифрован на PHP асимметричным алгоритмом RSA' > rsa.txt
Используем публичный и приватный ключ из предыдущего примера. Объявим шифруемый файл, шифрованный и расшифрованный:
$filePublicKey = 'public.crt'; $filePrivateKey = 'private.pem'; $file = 'rsa.txt'; $fileEncrypted = 'rsa-encrypted.txt'; $fileDecrypted = 'rsa-decrypted.txt';
По аналогии с предыдущими примерами: получаем публичный ключ $publicKey и с помощью него шифруем содержание файла $file. Результат записываем в $fileEncrypted:
$contentsPublicKey = file_get_contents($filePublicKey); $publicKey = openssl_get_publickey($contentsPublicKey); $contents = file_get_contents($file); openssl_public_encrypt($contents, $contentsEncrypted, $publicKey); file_put_contents($fileEncrypted, $contentsEncrypted);
Чтобы расшифровать этот файл: получаем приватный ключ $privateKey, расшифровываем содержимое файла $fileEncrypted. Данные записываем в файл $fileDecrypted:
$contentsPrivateKey = file_get_contents($filePrivateKey); $privateKey = openssl_get_privatekey($contentsPrivateKey); $contentsEncrypted = file_get_contents($fileEncrypted); openssl_private_decrypt($contentsEncrypted, $contentsDecrypted, $privateKey); file_put_contents($fileDecrypted, $contentsDecrypted);
$ cat rsa-decrypted.txt Этот файл был зашифрован на PHP асимметричным алгоритмом RSA
openssl_sign
openssl_sign() computes a signature for the specified data by generating a cryptographic digital signature using the private key associated with private_key . Note that the data itself is not encrypted.
Parameters
The string of data you wish to sign
If the call was successful the signature is returned in signature .
string - a PEM formatted key
string - a valid string returned by openssl_get_md_methods() example, "sha256WithRSAEncryption" or "sha384".
Return Values
Returns true on success or false on failure.
Changelog
Version Description 8.0.0 private_key accepts an OpenSSLAsymmetricKey or OpenSSLCertificate instance now; previously, a resource of type OpenSSL key or OpenSSL X.509 was accepted.
Examples
Example #1 openssl_sign() example
// $data is assumed to contain the data to be signed
?php
// fetch private key from file and ready it
$pkeyid = openssl_pkey_get_private ( "file://src/openssl-0.9.6/demos/sign/key.pem" );
// compute signature
openssl_sign ( $data , $signature , $pkeyid );
// free the key from memory
openssl_free_key ( $pkeyid );
?>
Example #2 openssl_sign() example
//data you want to sign
$data = 'my data' ;
?php
//create new private and public key
$new_key_pair = openssl_pkey_new (array(
"private_key_bits" => 2048 ,
"private_key_type" => OPENSSL_KEYTYPE_RSA ,
));
openssl_pkey_export ( $new_key_pair , $private_key_pem );
$details = openssl_pkey_get_details ( $new_key_pair );
$public_key_pem = $details [ 'key' ];
//create signature
openssl_sign ( $data , $signature , $private_key_pem , OPENSSL_ALGO_SHA256 );
//save for later
file_put_contents ( 'private_key.pem' , $private_key_pem );
file_put_contents ( 'public_key.pem' , $public_key_pem );
file_put_contents ( 'signature.dat' , $signature );
//verify signature
$r = openssl_verify ( $data , $signature , $public_key_pem , "sha256WithRSAEncryption" );
var_dump ( $r );
?>
See Also
User Contributed Notes 4 notes
This may help if you just want a real-simple private/public key pair:
$data = "Beeeeer is really good.. hic. " ;
// You can get a simple private/public key pair using:
// openssl genrsa 512 >private_key.txt
// openssl rsa -pubout public_key.txt
// IMPORTANT: The key pair below is provided for testing only.
// For security reasons you must get a new key pair
// for production use, obviously.
$private_key = -----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6zxqlVzz0wy2j4kQVUC4Z
RZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQJAL151ZeMKHEU2c1qdRKS9
sTxCcc2pVwoAGVzRccNX16tfmCf8FjxuM3WmLdsPxYoHrwb1LFNxiNk1MXrxjH3R
6QIhAPB7edmcjH4bhMaJBztcbNE1VRCEi/bisAwiPPMq9/2nAiEA3lyc5+f6DEIJ
h1y6BWkdVULDSM+jpi1XiV/DevxuijMCIQCAEPGqHsF+4v7Jj+3HAgh9PU6otj2n
Y79nJtCYmvhoHwIgNDePaS4inApN7omp7WdXyhPZhBmulnGDYvEoGJN66d0CIHra
I2SvDkQ5CmrzkW5qPaE2oO7BSqAhRZxiYpZFb5CI
-----END RSA PRIVATE KEY-----
EOD;
$public_key = -----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANDiE2+Xi/WnO+s120NiiJhNyIButVu6
zxqlVzz0wy2j4kQVUC4ZRZD80IY+4wIiX2YxKBZKGnd2TtPkcJ/ljkUCAwEAAQ==
-----END PUBLIC KEY-----
EOD;
// At least with PHP 5.2.2 / OpenSSL 0.9.8b (Fedora 7)
// there seems to be no need to call openssl_get_privatekey or similar.
// Just pass the key as defined above
openssl_sign ( $data , $binary_signature , $private_key , OPENSSL_ALGO_SHA1 );
// Check signature
$ok = openssl_verify ( $data , $binary_signature , $public_key , OPENSSL_ALGO_SHA1 );
echo "check #1: " ;
if ( $ok == 1 ) echo "signature ok (as it should be)\n" ;
> elseif ( $ok == 0 ) echo "bad (there's something wrong)\n" ;
> else echo "ugly, error checking signature\n" ;
>
$ok = openssl_verify ( 'tampered' . $data , $binary_signature , $public_key , OPENSSL_ALGO_SHA1 );
echo "check #2: " ;
if ( $ok == 1 ) echo "ERROR: Data has been tampered, but signature is still valid! Argh!\n" ;
> elseif ( $ok == 0 ) echo "bad signature (as it should be, since data has beent tampered)\n" ;
> else echo "ugly, error checking signature\n" ;
>
It should be noted that the default signature algorithm used by openssl_sign() and openssl_verify (OPENSSL_ALGO_SHA1) is no longer supported by default in OpenSSL Version 3 series.
With an up to date OpenSSL library, one has to run
"update-crypto-policies --set LEGACY"
on the server where the library resides in order to allow these functions to work without the optional alternative algorithm argument.
The list of Signature Algorithms (constants) is very limited! Fortunately the newer versions of php/openssl allow you to specify the signature algorithm as a string.
You can use the 'openssl_get_md_methods' method to get a list of digest methods. Only some of them may be used to sign with RSA private keys.
Those that can be used to sign with RSA private keys are: md4, md5, ripemd160, sha, sha1, sha224, sha256, sha384, sha512
Here's the modified Example #1 with SHA-512 hash:
// $data is assumed to contain the data to be signed
// fetch private key from file and ready it
$fp = fopen ( "/src/openssl-0.9.6/demos/sign/key.pem" , "r" );
$priv_key = fread ( $fp , 8192 );
fclose ( $fp );
$pkeyid = openssl_get_privatekey ( $priv_key );
// compute signature with SHA-512
openssl_sign ( $data , $signature , $pkeyid , "sha512" );
// free the key from memory
openssl_free_key ( $pkeyid );
?>