Использование вектора инициализации в openssl_encrypt

Я просмотрел этот вопрос и хотел сделать это для себя. Когда я запустил этот код (взятый прямо из этого ответа):

$textToEncrypt = "My super secret information.";
$encryptionMethod = "AES-256-CBC";  // AES is used by the U.S. gov't to encrypt top secret documents.
$secretHash = "25c6c7ff35b9979b151f2136cd13b0ff";

//To encrypt
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash, '1234567812345678');

//To Decrypt
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secretHash);

//Result
echo "Encrypted: $encryptedMessage <br>Decrypted: $decryptedMessage";

Однако я получаю предупреждение

openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended

Итак, я пошел и посмотрел docs, но там нет документации. Я нашел этот комментарий, но до сих пор не упоминал, что должен представлять собой Инициализационный вектор и как я должен его использовать. Может ли кто-нибудь просветить меня?

Я знаю, что мог бы сделать еще несколько Google, но Stackoverflow появляется во многих результатах поиска. Я думал, что этот вопрос может быть полезен для всех, кто имел эту проблему.

Ответ 1

IV обычно представляет собой случайное число, гарантирующее, что зашифрованный текст уникален.

Чтобы объяснить, зачем это нужно, пусть притворяется, что у нас есть база данных имен людей, зашифрованных ключом "секрет" и без IV.

1 John dsfa9p8y098hasdf
2 Paul po43pokdfgpo3k4y
3 John dsfa9p8y098hasdf

Если Джон 1 знает свой шифрованный текст (dsfa9p8y098hasdf) и имеет доступ к другим текстам шифрования, он может легко найти других людей по имени Джон.

Теперь на самом деле режим шифрования, требующий IV, всегда будет использовать его. Если вы не укажете IV, он автоматически установит пучок нулевых байтов. Представьте первый пример, но с константой IV (00000000).

1 John dsfa9p8y098hasdf 00000000
2 Paul po43pokdfgpo3k4y 00000000
3 John dsfa9p8y098hasdf 00000000

Чтобы предотвратить повторные шифрованные тексты, мы можем зашифровать имена, используя один и тот же "секретный" ключ и случайные IV:

1 John sdf875n90mh28458 45gh3546
2 Paul fg9087n5b60987nf 56897ngq
3 John gjhn0m89456vnler 8907345f

Как вы можете видеть, два текста шифрования "Джон" теперь разные. Каждый IV уникален и повлиял на процесс шифрования, что делает конечный результат уникальным. Джон 1 теперь не имеет понятия, какое имя пользователя 3.

Для дешифрования требуется использование того же самого IV, который был зашифрован, конечно, поэтому он должен храниться в базе данных. IV бесполезен без ключа, поэтому передача или хранение его с зашифрованным текстом не вызывает беспокойства.

Это слишком упрощенный пример, но, правда, не использование IV имеет серьезные последствия для безопасности.


Теперь ваш код, как представляется, устанавливает IV (1234567812345678), но не использует его при расшифровке. Это наверняка потерпит неудачу.

Вы также можете использовать некоторые функции генерации PHP IV. Я думаю, это должно сработать для вас:

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash, 0, $iv);
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secretHash, 0, $iv);

Для хранения/передачи вы можете просто объединить текст IV и шифрования так:

$data = $iv.$encryptedMessage;

Затем при извлечении вытащите IV для расшифровки:

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = substr($data, 0, $iv_size);
$decryptedMessage = openssl_decrypt(substr($data, $iv_size), $encryptionMethod, $secretHash, 0, $iv);

Для получения дополнительной информации посетите библиотеку PHP Mcrypt. Он довольно полнофункциональный и содержит множество примеров, многие из которых могут помочь вам с реализациями шифрования openssh. http://php.net/manual/en/function.mcrypt-encrypt.php