Раньше мне удалось перенести некоторый CBC-код C ++ CryptoPP Rijndael_128 на MCrypt PHP, но теперь у меня проблемы с режимом CFB. Результаты C ++ и PHP не совпадают (ну, первые байтовые совпадения, но это может быть совпадением, а все остальное – нет). С некоторыми диагностиками, похоже, что mcrypt PHP не правильно задает длину ключа?
Вот C ++ (диагностика и утилизаторы удалены для простоты):
CFB_Mode<AES>::Encryption encryptor(g_encrypt_key, AES::DEFAULT_KEYLENGTH, g_encrypt_iv); StringSource ss( sInput.c_str(), true, new StreamTransformationFilter( encryptor, new HexEncoder( new StringSink( sEncryptedOut ) ) ));
И вот PHP:
$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CFB, '') mcrypt_generic_init($cipher, $g_encrypt_key, $g_encrypt_iv); $sEncryptedOutput = mcrypt_generic( $cipher, $sInput); mcrypt_generic_deinit($cipher); mcrypt_module_close($cipher);
g_encrypt_key
и g_encrypt_iv
имеют g_encrypt_iv
16 байтов, а байты соответствуют версиям C ++ и PHP. Для версии PHP это двоичная строка, построенная из байтов (да, я проверил, что они идентичны).
Я добавил вызовы к версии PHP для проверки размера блока, размера ключа и т. Д. Размер блока и размер iv равны 16; поддерживаемые размеры клавиш сообщаются как 16, 24 и 32 – все, как ожидалось.
Там, где я думаю, проблема заключается в том, что keyize сообщается как 32 байта. Глядя на документы mcrypt, единственным способом настройки ключа является предоставление ключа требуемого размера. Но я передаю 16-байтовый ключ! Итак, почему он сообщает о наличии 32-байтового ключа? Если режим CFB должен использовать 32-байтовый ключ, то почему CryptoPP принимает его как хорошо? Каково решение? Могу ли я заставить PHP использовать 16-байтовый ключ, который был предоставлен? Или есть параметр, который мне не хватает, который по умолчанию отличается от другого параметра в CryptoPP, чем в MCrypt?
Я использую режим CFB, потому что хочу свести к минимуму длину результирующих зашифрованных данных. Несколько байтов, которые будут добавляться в дополнение, имеют значение в этом приложении.
Мне нужно иметь возможность шифровать / расшифровывать в C ++, но только шифровать в PHP. AES, возможно, слишком велико для моего приложения – минимальное значение, которое мне нужно, – «хорошее скремблирование байтов», так что функция отдельных байтов в данных не очевидна.
Прошло некоторое время, но у меня были некоторые подобные проблемы с mcrypt и openSSL, использующие CFB пару лет назад. В конце концов, я обнаружил, что mcrypt использовал другой размер цепи обратной связи по умолчанию, чем openssl в режиме CFB. То есть, я считаю, что openSSL AES128 в CFB использовал размер блока и размер обратной связи 128 бит, в то время как mcrypt использовал размер блока 128 бит и размер обратной связи 8 бит. У меня нет возможности подтвердить это, это было просто предположение в то время, когда вы читали старые сообщения на форуме. Независимо от правды этой теории, я был не единственным человеком или первым, кто имел эту проблему.
Решение для меня состояло в том, чтобы использовать nOFB как вы. Согласно справочной библиотеке PHP mcrypt, MCRYPT_MODE_NOFB
заставляет цепочку обратной связи равняться размеру блока алгоритма, в этом случае 128-битный блок / обратная связь для AES128 (Rijndael), который соответствует тому, что в manpage для модуля mcrypt говорится о nOFB. Это хорошо, поскольку все, что я нашел, говорит, что обратная связь nOFB синхронна с размером блока. Таким образом, как mcrypt, так и OpenSSL в nOFB теперь были 128-битными ключами / iv / block / feedback для AES128, и все работало нормально.
Что касается PHP-отчетности 256-битных ключей (32 байта), функция, которая возвращает текущий размер ключа ключа шифрования, фактически возвращает максимальный размер ключа, что явно не указано в документации. Я знаю это, потому что мой маленький класс, который я использую все время для разных проектов, отлично работает с openSSL и любыми другими AES-библиотеками в CBC или nOFB. Это было бы не так, если бы mcrypt заполнял мой 128-битный (16 символов) ключом с дополнительными 128 бит нулевой строки или что-то еще и не был бы технически корректным.
Не совсем хороший ответ, но лучшее, что я получил на основе очень любительского набега на криптографию несколько лет назад.
Проверьте phpseclib:
http://phpseclib.sourceforge.net/
Вы можете установить размер ключа и размер блока так, как хотите.
например. $ aes-> setKeyLength (128) или $ aes-> setKeyLength (256);
У меня была эта проблема – пара баллов. По умолчанию режим PHP Rijndael устанавливает цикл обратной связи на 8 бит – для AES должна быть такая же длина, как и IV / Key.
Вы можете сделать это, используя режим «ncfb» вместо «cfb» или MCRYPT_MODE_CFB.
Полная информация о написании aes_cfb_128 совместимых PHP находится в этом вопросе Security Stackexchange: aes cfb 128 проблема дешифрования / шифрования между Erlang и PHP . Короче это (от Тома Лика):
… для CFB и OFB (которые отличаются друг от друга и не могут использоваться взаимозаменяемо), вам нужно беспокоиться о «длине обратной связи», которая не обязательно документируется с высокой четкостью в различных криптографических библиотеках. Для шифрования и дешифрования необходимо использовать одну и ту же длину обратной связи для взаимодействия.