Основные факты:
$algorithm = MCRYPT_BLOWFISH; $mode = MCRYPT_MODE_CBC; $randSource = MCRYPT_DEV_URANDOM;
Примечание. Это не является строгим вопросом кодирования.
Контекст:
CentOS 7, Apache 2.4.12 и PHP 5.6.20.
Я делаю HTML-адрес электронной почты с ссылкой «подтвердить свой адрес электронной почты», что позволяет завершить процесс регистрации. Все, что находится на моем виртуальном частном сервере, это UTF-8, и все входные данные формы и строки запроса обрабатываются с помощью многобайтовых (mb) функций.
Задний план
В качестве эксперимента ( я знаю о возрасте и состоянии библиотеки mcrypt ), я пытаюсь расшифровать зашифрованные параметры строки запроса Blowfish. Предположим, что по пути вверх последовательность шифрования работает отлично, и я получаю электронную почту по ссылке.
По пути вниз, hmac_hash()
(SHA-512, только для этого эксперимента) работает, и я могу отделить каждое независимое сообщение (32 символа) от его хэш-контрольной суммы (128 символов). Базовое декодирование разделенной части сообщения работает. Для каждого параметра я оставляю составной текст шифрования , где составной текст шифрования равен базовому шифрному тексту IV + . Предположим, что я использую версию substr()
для получения IV и базового текста шифрования независимо (что является парным для курса).
проблема
PHP: Warning mcrypt_generic_init(): Iv size is incorrect; supplied length: 12, needed: 8
Предположим, что я применил руководство PHP и Stackoverflow. Предположим, я посмотрел на другие вопросы, похожие, но не так, как этот. Предположим, что я искал Интернет безрезультатно. Предположим, у меня достаточно опыта для правильной настройки mb_string
. Предположим, что я позабочусь о заполнении mcrypt, когда я пройду эту текущую проблему.
Могут ли проблемы с несколькими байтами вмешиваться в дешифрование?
Может ли base64 кодировать IV + base cipher text
шифрования IV + base cipher text
испортив IV?
Может ли ошибка base64 быть проблемой?
Должен ли я указывать более конкретный MCRYPT_BLOWFISH_*
?
Почему размер blowfish IV составляет 8 байтов, но редко дает 8-байтный IV?
Какой substr () следует использовать, substr()
или mb_substr()
, для настройки, которая опирается на создание всего UTF-8 и обрабатывает все остальные входные данные как многобайтовые UTF-8. Я знаю, что это странный вопрос, но во всех примерах последовательности расшифровки скриптов PHP Manual используется substr () , и ни один из них не использует mb_substr()
. Все, что на моем сайте работает с mb_functions, когда это возможно, и я бы не прочь использовать substr()
если он решил мою проблему, но он не решает проблему. Когда я использую mb_substr()
, я получаю следующее предупреждение.
PHP: Warning mcrypt_generic_init(): Iv size is incorrect; supplied length: 11, needed: 8
Есть ли у кого-нибудь опыт в этой конкретной проблеме? Конструктивные ответы будут вознаграждены!
Последний
Выше приведен пример хэша Blowfish, который я пытаюсь восстановить из массива, полученного через SHA512 HMACed, симметрично Blowfish зашифрованный (CBC), безопасный для кодировки Base64, urlencoded, строку запроса (phew!).
Ниже показано, что строки для строки запроса (нарезанные хэшем blowfish) выглядят как после шифрования, подписи и кодировки base64, но до того, как они были ранжированы. Каждый из них имеет длину 128 символов (каждая строка становится длиннее, поскольку вы делаете больше вещей).
Выше представлен декодированный Base64 и расшифрованный массив Blowfish, полученный из строки запроса (Очевидно, что между этим результатом есть шаги безопасности, но я просто пытаюсь показать последнее состояние вещей.) Что-то не так. Шифрование, похоже, работает без ошибок. Расшифровка также не вызывает ошибок. Обычный текст просто неправильный. Если я присоединяюсь / вставляю эти элементы, они не будут похожи на хеш Blowfish выше.
Я бы предположил, что проблема скроется где-то с кодировкой UTF-8, поскольку вы используете ее в неправильных контекстах. Также может быть, что ваши фреймворки делают некоторые магии для всех случаев использования. Это может быть слишком много и, как правило, заканчивается защитой или просто такими ошибками, поскольку вы не делаете то, что действительно нужно делать, когда это действительно нужно сделать.
Строки в PHP – это просто коллекции байтов. Вы можете хранить текст там, в кодировке по вашему выбору или просто хранить двоичные данные там, например изображения. PHP не знает, какие данные находятся в какой строке, и какая кодировка используется там. Это необходимо разработчику для отслеживания этой информации.
При работе с шифрованием вы получаете двоичные данные при генерации случайных строк или шифровании некоторых полезных нагрузок. Он сохраняется в строках, но у него нет кодировки UTF-8, так как это всего лишь байты. Я бы даже не сказал, что это кодировка ISO-8859-1, так как это означает, что байт 77 (0x4D) обозначает букву «M». Но на самом деле, это просто цифры – 77 не означает никакого письма вообще.
Еще одна вещь для добавления – для символов ASCII (латинские буквы, цифры и т. Д. – значения 0-127 байтов) для представления этого символа в кодировке UTF-8 требуется один байт (тот же, что и в ISO-8859). Итак, насколько вы передаете данные base64_encode
d, вы не должны слишком беспокоиться об этом. mb_substr
также будет работать так же, как и substr
. Но! для двоичных данных вы не можете использовать функции mb_*
, поскольку это работает с символами. Например, если зашифрованные данные представляют собой два байта 0xC5 0xA1
, это единственный символ в UTF-8. Шифрование работает с байтами (вплоть до конечного результата, который может быть чем угодно – даже двоичных файлов), а не символов.
Поскольку вы не указали какой-либо код, я поместил некоторые для вас – я надеюсь, что это поможет с вашей проблемой (если это все еще актуально).
Чтобы показать параметры передачи в URL-адресе, есть два файла: encrypt.php
и decrypt.php
. Сохраните в каталог, запустите php -S localhost:8000
и перейдите по адресу http: // localhost: 8000 / encrypt.php
encrypt.php
:
<?php // mcrypt_enc_get_key_size($td) gives 56, so it's longest that this key can be $key = 'LedsoilgarvEwAbDavVenpirabUfjaiktavKekjeajUmshamEsyenvoa'; $data = 'This is very important data, with some š UTF-8 ĘĖ symbols'; $td = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, ''); // create random IV - it's just random 8 bytes. You should use random_bytes() instead if available $ivSize = mcrypt_enc_get_iv_size($td); $iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM); mcrypt_generic_init($td, $key, $iv); $encrypted = mcrypt_generic($td, $data); mcrypt_generic_deinit($td); mcrypt_module_close($td); // payload that you want to send - binary. It's neither UTF-8 nor ISO-8859-1 - it's just bytes $payload = $iv . $encrypted; // base64 to pass safely $base64EncodedPayload = base64_encode($payload); // URL encode for URL. No need to do both URL-safe base64 *and* base64 + urlencode $link = 'http://localhost:8000/decrypt.php?encryptedBase64=' . urlencode($base64EncodedPayload); // in fact, just for the reference, you don't even need base64_encode - urlencode also works at byte level // base64_encode takes about 1.33 more space, but urlencode takes 3 times more than original for non-safe symbols, so base_64 will probably be shorter $link2 = 'http://localhost:8000/decrypt.php?encrypted=' . urlencode($payload); ?> <!doctype html> <html> <head> <meta charset="utf-8"> </head> <body> <pre><?php var_dump('Data:', $data); var_dump('Data size in bytes:', strlen($data)); var_dump('Data size in characters - smaller, as 3 of the characters take 2 bytes:', mb_strlen($data, 'UTF-8')); var_dump('Encrypted data size in bytes - same as original:', strlen($encrypted)); var_dump('Encrypted data size in characters - will be pseudo-random each time:', mb_strlen($encrypted, 'UTF-8')); var_dump('IV base64 encoded:', base64_encode($iv)); var_dump('Encrypted string base64 encoded:', base64_encode($encrypted)); ?></pre> <!-- Link will not contain any special characters, so htmlentities should not make any difference --> <!-- In any case, I would still recommend to use right encoding at the right context to avoid any issues if something changes --> <a href="<?php echo htmlentities($link, ENT_QUOTES, 'UTF-8');?>">Link to decrypt</a><br/> <a href="<?php echo htmlentities($link2, ENT_QUOTES, 'UTF-8');?>">Link to decrypt2</a> </body> </html>
decrypt.php
:
<?php $key = 'LedsoilgarvEwAbDavVenpirabUfjaiktavKekjeajUmshamEsyenvoa'; if (isset($_GET['encryptedBase64'])) { // just get base64_encoded symbols (will be ASCII - same in UTF-8 or other encodings) $base64EncodedPayload = $_GET['encryptedBase64']; $payload = base64_decode($base64EncodedPayload); } else { // just get binary string from URL $payload = $_GET['encrypted']; } $td = mcrypt_module_open(MCRYPT_BLOWFISH, '', MCRYPT_MODE_CBC, ''); $ivSize = mcrypt_enc_get_iv_size($td); $iv = substr($payload, 0, $ivSize); $encrypted = substr($payload, $ivSize); mcrypt_generic_init($td, $key, $iv); /* Decrypt encrypted string */ $decrypted = mdecrypt_generic($td, $encrypted); /* Terminate decryption handle and close module */ mcrypt_generic_deinit($td); mcrypt_module_close($td); ?> <!doctype html> <html> <head> <meta charset="utf-8"> </head> <body> <pre><?php var_dump('IV base64 encoded:', base64_encode($iv)); var_dump('Encrypted string base64 encoded:', base64_encode($encrypted)); var_dump('Result:', $decrypted); ?></pre> </body> </html>