Шифрование AES в PHP и ColdFusion9 дает разные результаты. Может кто-нибудь, пожалуйста, помогите мне?
Следующий PHP-код
$key = "12345678123456781234567812345678"; $iv = "1234567812345678"; $data = "This is a plain string."; echo base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv));
дает мне G + tdEOfQTtVCQGxW3N5uzkqN207OyfIPxS6zf2xrKKY =
Хотя ниже код ColdFusion
<cfset thePlainData = "This is a plain string." /> <cfset theKey = "12345678123456781234567812345678" /> <cfset theAlgorithm = "AES/CBC/PKCS5Padding" /> <cfset theEncoding = "base64" /> <cfset theIV = "1234567812345678" /> <cfset encryptedString = encrypt(thePlainData, theKey, theAlgorithm, theEncoding, theIV) />
дает мне KLt55n5 / T3ee6xVq9VGFbyCacJznkHEqC / RDRhL + 4nw =
Любая идея, где я ошибаюсь? Заранее спасибо.
К сожалению, существует небольшая несовместимость между версиями ColdFusion и PHP в отношении используемого стиля заполнения открытого текста. AES требует, чтобы размер блочного текста делился на 128. Чтобы достичь этого, PHP будет заполнять ввод открытого текста с NULL-символами, чтобы получить правильный размер блока. ColdFusion может использовать различные методы заполнения, которые поддерживаются Java . К сожалению, ColdFusion или Java поддерживают схему дополнений NULL, которая затрудняет взаимодействие. Обработка строк ColdFusion не поддерживает NULL-символы, поэтому вам нужно будет внедрить схему PKCS5Padding в PHP вместо того, чтобы заставить их правильно взаимодействовать.
Кроме того, как упоминалось в комментариях, ColdFusion ожидает, что ключ будет закодирован в base64, поэтому вам понадобится ключевой параметр:
<cfset theKey = toBase64("12345678123456781234567812345678") />
Кроме того, Java по умолчанию (и ColdFusion по расширению) поддерживает только размеры ключей до 128 бит. Здесь вы используете 256-битный ключ, который потребует расширения Java Unlimited Strength (для тех, кто пытается протестировать код и получить недопустимую ошибку размера ключа).
Полученный PHP-код выглядит так:
// Function from http://us3.php.net/manual/en/ref.mcrypt.php#69782 function pkcs5_pad ($text, $blocksize) { $pad = $blocksize - (strlen($text) % $blocksize); return $text . str_repeat(chr($pad), $pad); } $key = "12345678123456781234567812345678"; $iv = "1234567812345678"; // Pad data with PKCS #5 to prevent PHP from using NULL padding. $data = pkcs5_pad("This is a plain string.", 16); echo base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv));
Полученный код ColdFusion выглядит так:
<cfset thePlainData = "This is a plain string." /> <cfset theKey = toBase64("12345678123456781234567812345678") /> <cfset theAlgorithm = "AES/CBC/PKCS5Padding" /> <cfset theEncoding = "base64" /> <cfset theIV = "1234567812345678" /> <cfset encryptedString = encrypt(thePlainData, theKey, theAlgorithm, theEncoding, theIV) /> <cfoutput>#encryptedString#</cfoutput>
Оба выводят одну и ту же строчную кодировку base64:
G+tdEOfQTtVCQGxW3N5uzlu0mGabRKNxuIdAXArQE80=
Я знаю, что это старая нить, но аналогичный вопрос возник недавно.
Хотя он не поддерживается изначально, выясняется, что существует способ создания нулевого заполнения в CF. Этот ответ Artjom B. соглашается, что проще всего отрегулировать заполнение в PHP, но указывает, что вы можете достичь того же результата, заполняя простой текст с помощью 0x00, до кратного размера блока алгоритма и используя схему «NoPadding».
Получение нулевых символов в CF немного сложно, но может быть сделано с использованием URLDecode («% 00») . Поскольку encrypt () всегда обрабатывает ввод как кодированный UTF-8, вы также можете использовать charsetEncode () для создания нулевого символа из массива байтов одного элемента, то есть charsetEncode( javacast("byte[]", [0] ), "utf-8")
.
Не очень тестирован, но что-то вроде этого должно привести к тому же результату в CF10:
Код:
thePlainData = nullPad("This is a plain string.", 16); // NB: JCE unlimited policy files required for 256 bit keys theKey = toBase64("12345678123456781234567812345678"); theIV = "1234567812345678"; encryptedString = encrypt(thePlainData, theKey, "AES/CBC/NoPadding", "base64", theIV);
Результат:
G+tdEOfQTtVCQGxW3N5uzkqN207OyfIPxS6zf2xrKKY=
Функция:
/* Pads a string, with null bytes, to a multiple of the given block size @param plainText - string to pad @param blockSize - pad string so it is a multiple of this size @param encoding - charset encoding of text */ string function nullPad( string plainText, numeric blockSize, string encoding="UTF-8") { local.newText = arguments.plainText; local.bytes = charsetDecode(arguments.plainText, arguments.encoding); local.remain = arrayLen( local.bytes ) % arguments.blockSize; if (local.remain neq 0) { local.padSize = arguments.blockSize - local.remain; local.newText &= repeatString( urlDecode("%00"), local.padSize ); } return local.newText; }