Использование PHP mcrypt с Rijndael / AES

Я пытаюсь зашифровать некоторые текстовые сообщения, используя mcrypt от php и шифрования Rijndael, но я не уверен в MCRYPT_MODE_modename (согласно руководству PHP они доступны «ecb», «cbc», «cfb», «ofb», nofb "или" stream ", но я читал, что на самом деле еще несколько). Я понятия не имею, что делают каждый или как их использовать.

Я читал две вещи, что режим ECB не должен использоваться, а MCRYPT_RAND – нет. Они не объяснили, почему. Для режима ECB я предполагаю, что это потому, что он всегда генерирует один и тот же зашифрованный вывод для одного и того же обычного текста (возможно, это может быть использовано для атаки), не знаю о MCRYPT_RAND (упоминается здесь @azz здесь ).

Мой вопрос в том, какой режим mcrypt я должен использовать, и было бы здорово увидеть пример использования PHP-кода, потому что все примеры, которые я нашел, используют ECB. Строки, которые я пытаюсь зашифровать, будут содержать только текст ascii и переменную длину, не более 500 символов.

ecb является самым простым и имеет недостатки, поэтому его не рекомендуется ( http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation ). cbc считается значительно более сильным, чем ecb. Некоторые из других могут быть даже сильнее, чем cbc, но все они связаны с потоком, поэтому cbc должен соответствовать вашим потребностям.

Из … http://us.php.net/manual/en/mcrypt.constants.php

  • MCRYPT_MODE_ECB (электронная кодовая книга) подходит для случайных данных, таких как шифрование других ключей. Поскольку данные короткие и случайные, недостатки ЕЦБ имеют благоприятный негативный эффект.
  • MCRYPT_MODE_CBC (цепочки блоков шифрования) особенно подходит для шифрования файлов, где безопасность значительно увеличивается над ECB.
  • MCRYPT_MODE_CFB (шифровальная обратная связь) является лучшим режимом для шифрования байтовых потоков, где должны быть зашифрованы одиночные байты.
  • MCRYPT_MODE_OFB (выходная обратная связь в 8 бит) сопоставима с CFB, но может использоваться в приложениях, где распространение ошибок нельзя допускать. Это небезопасно (потому что он работает в режиме 8 бит), поэтому его не рекомендуется использовать.
  • MCRYPT_MODE_NOFB (выходная обратная связь, в nbit) сопоставима с OFB, но более безопасна, поскольку она работает с размером блока алгоритма.
  • MCRYPT_MODE_STREAM – дополнительный режим для включения некоторых алгоритмов потока, таких как «WAKE» или «RC4».

Я не уверен, почему рекомендуется MCRYPT_RAND, но может случиться так, что генератор случайных чисел системы на многих системах не считается действительно случайным. Есть только две альтернативы, и они могут быть недоступны в зависимости от вашей системы и версии PHP. Из … http://php.net/manual/en/function.mcrypt-create-iv.php

  • Источником IV может быть MCRYPT_RAND (генератор случайных чисел системы), MCRYPT_DEV_RANDOM (чтение данных из / dev / random) и MCRYPT_DEV_URANDOM (чтение данных из / dev / urandom). До 5.3.0 MCRYPT_RAND был единственным, поддерживаемым в Windows.

Код ниже – это просто образец. Он работает, но я не могу подтвердить его силу.


 <? PHP

 // Тестовый код

     $ objEncManager = новый DataEncryptor ();

     $ sensitiveData = "7890";
     echo "Исходные данные: _".  $ sensitiveData.  "_ <br> <br>";

     $ encryptedData = $ objEncManager-> mcryptEncryptString ($ sensitiveData);
     echo "Enc Data: _".  $ encryptedData.  "_ <br> <br>";
     echo "Enc Data length:".  strlen ($ encryptedData).  "На <br>";

     $ decryptedData = $ objEncManager-> mcryptDecryptString ($ encryptedData, $ objEncManager-> lastIv);
     echo "D-enc Data: _".  $ decryptedData.  "_ <br> <br>";

     эхо "IV: _".  $ objEncManager-> lastIv.  "_ <br> <br>";


 / *
  * Примечание. Эти функции не точно обрабатывают случаи, когда данные 
  * зашифрованные имеют завершающие пробелы, поэтому данные
  * зашифрованные ими не должны быть.  Ведущие пробелы - все в порядке.
  *  
  * Примечание. Если ваши данные должны быть переданы через небезопасный безопасный носитель, вы должны
  * base64_encode, но это делает данные примерно на 33% больше.
  * 
  * Примечание. Расшифровка IV должна быть такой же, как шифрование IV, поэтому шифрование
  * IV должен храниться или передаваться с зашифрованными данными.
  * От (http://php.net/manual/en/function.mcrypt-create-iv.php) ... 
  * «IV предназначен только для предоставления альтернативного семени для процедур шифрования. 
  * Этот IV не обязательно должен быть секретным, хотя это может быть желательно. 
  * Вы даже можете отправить его вместе с вашим зашифрованным текстом без потери безопасности ».
  * 
  * Примечание. Эти методы не делают никакой проверки ошибок на успех различных функций mcrypt
  * /
 класс DataEncryptor
 {
     const MY_MCRYPT_CIPHER = MCRYPT_RIJNDAEL_256;
     const MY_MCRYPT_MODE = MCRYPT_MODE_CBC;
     const MY_MCRYPT_KEY_STRING = "1234567890-abcDEFGHUzyxwvutsrqpo";  // Это должна быть случайная строка, рекомендуется 32 байта

     public $ lastIv = '';


     публичная функция __construct ()
     {
         // ничего не делать
     }


     / **
      * Принимает строку открытого текста и возвращает зашифрованную версию
      * /
     public function mcryptEncryptString ($ stringToEncrypt, $ base64encoded = true)
     {
         // Установите вектор инициализации
             $ iv_size = mcrypt_get_iv_size (self :: MY_MCRYPT_CIPHER, self :: MY_MCRYPT_MODE);
             $ iv = mcrypt_create_iv ($ iv_size, MCRYPT_RAND);
             $ this-> lastIv = $ iv;

         // Шифрование данных
             $ encryptedData = mcrypt_encrypt (self :: MY_MCRYPT_CIPHER, self :: MY_MCRYPT_KEY_STRING, $ stringToEncrypt, self :: MY_MCRYPT_MODE, $ iv);

         // Данные могут нуждаться в передаче через недвоичный безопасный носитель, поэтому base64_encode при необходимости.  (делает данные примерно на 33% больше)
             if ($ base64encoded) {
                 $ encryptedData = base64_encode ($ encryptedData);
                 $ this-> lastIv = base64_encode ($ iv);
             } else {
                 $ this-> lastIv = $ iv;
             }

         // Возвращение зашифрованных данных
             return $ encryptedData;
     }


     / **
      * Принимает строку открытого текста и возвращает зашифрованную версию
      * /
     public function mcryptDecryptString ($ stringToDecrypt, $ iv, $ base64encoded = true)
     {
         // Примечание: расшифровка IV должна быть такой же, как и шифрование IV, поэтому шифрование IV должно храниться во время шифрования

         // Возможно, данные были base64_encoded, поэтому при необходимости декодировать их (необходимо пройти перед расшифровкой)
             if ($ base64encoded) {
                 $ stringToDecrypt = base64_decode ($ stringToDecrypt);
                 $ iv = base64_decode ($ iv);
             }

         // Расшифровать данные
             $ decryptedData = mcrypt_decrypt (self :: MY_MCRYPT_CIPHER, self :: MY_MCRYPT_KEY_STRING, $ stringToDecrypt, self :: MY_MCRYPT_MODE, $ iv);

         // Возвращаем дешифрованные данные
             return rtrim ($ decryptedData);  // rtrim необходимо для удаления дополнений, добавленных во время шифрования
     }


 }
 ?>

Режим ЕЦБ не является безопасным, поскольку он не вводит случайность в зашифрованные данные. Это в основном означает, что вы увидите те же шаблоны ввода на выходе (т. Е. См. Изображение, представленное здесь , это «зашифрованная» версия Tux, логотип Linux).

MT_RAND не считается защищенным, так как он использует генератор случайных чисел для операционной системы (функция rand() PHP).

Для криптографических целей лучше использовать MCRYPT_DEV_RANDOM (читать данные из / dev / random) или MCRYPT_DEV_URANDOM (читать данные из / dev / urandom).

Наиболее часто используемые и безопасные режимы шифрования, доступные в Mcrypt, являются режимами CBC и CTR и подходят для общего использования. Всегда лучше использовать шифрование + аутентификацию (т.е. шифрование, а затем аутентификацию с использованием HMAC). Например, режим CBC без аутентификации зависит от атаки Padding Oracle .