Я разобрался в своей проблеме. Короткий ответ: используемый ключ был разной длины в Какао и PHP. Длинный ответ ...
В моем первоначальном запросе использовался Blowfish / CBC, представляющий собой шифр с переменной длиной ключа от 16 байт до 56. Исходя из идеи Боаза, что ключ каким-то образом виноват, я переключился на TripleDES для шифра, поскольку он использует фиксированный ключ. длина 24 байта. Тогда я заметил проблему: ключ, возвращаемый Cocoa / EVP_BytesToKey (), имел длину 24 байта, но значение, возвращаемое md5 (), хэшировавшим мой ключ, было только 16.
Решение проблемы состояло в том, чтобы PHP создавал ключ точно так же, как EVP_BytesToKey
, пока длина вывода не будет хотя бы минимальной (cipherKeyLength + cipherIVLength). Следующий PHP делает именно это (игнорируя любые итерации или подсчет)
$cipher = MCRYPT_TRIPLEDES;
$cipherMode = MCRYPT_MODE_CBC;
$keySize = mcrypt_get_key_size( $cipher, $cipherMode );
$ivSize = mcrypt_get_iv_size( $cipher, $cipherMode );
$rawKey = "ThisIsMyKey";
$genKeyData = '';
do
{
$genKeyData = $genKeyData.md5( $genKeyData.$rawKey, true );
} while( strlen( $genKeyData ) < ($keySize + $ivSize) );
$generatedKey = substr( $genKeyData, 0, $keySize );
$generatedIV = substr( $genKeyData, $keySize, $ivSize );
$output = mcrypt_decrypt( $cipher, $generatedKey, $encodedData, $cipherMode, $generatedIV );
echo "output (hex)" . bin2hex($output);
Обратите внимание, что, скорее всего, в конце этого вывода будет заполнение PKCS # 5. Ознакомьтесь с комментариями здесь http://us3.php.net/manual/en/ref.mcrypt.php для pkcs5_pad
и pkcs5_unpad
для добавления и удаления указанных отступов.
В основном, возьмите необработанное значение md5 ключа, и, если этого недостаточно, добавьте ключ к результату md5 и снова md5 эту строку. Вымойте, промойте, повторите. Страница man для EVP_BytesToKey () объясняет, что он на самом деле делает, и показывает, где можно поместить значения соли, если это необходимо. Этот метод восстановления ключа также правильно восстанавливает вектор инициализации (iv), поэтому нет необходимости передавать его.
А как насчет Blowfish?
EVP_BytesToKey()
возвращает наименьший возможный ключ для шифра, так как он не принимает контекст, на котором основывается размер ключа. Таким образом, размер по умолчанию - это все, что вы получаете, что для Blowfish составляет 16 байт. mcrypt_get_key_size()
, с другой стороны, возвращает максимально возможный размер ключа. Итак, следующие строки в моем исходном коде:
$keySize = mcrypt_enc_get_key_size( $td );
$key = substr( md5( "ThisIsMyKey" ), 0, $keySize );
всегда будет возвращать 32-символьный ключ, потому что $ keySize установлен на 56. Изменив код выше на:
$cipher = MCRYPT_BLOWFISH;
$cipherMode = MCRYPT_MODE_CBC;
$keySize = 16;
позволяет Blowfish правильно декодировать, но в значительной степени разрушает преимущество ключа переменной длины. Подводя итог, EVP_BytesToKey()
не работает, когда дело доходит до шифров с переменной длиной ключа. Вам необходимо создать ключ / iv по-разному при использовании шифра с переменным ключом. Я не стал вдаваться в подробности, потому что 3DES будет работать для того, что мне нужно.