Ошибки дешифрования данных as3crypto blowfish в PHP
В данный момент я немного новичок в ActionScript 3 и пытаюсь использовать библиотеку as3crypto для шифрования некоторых данных с помощью алгоритма blowfish перед отправкой их на сервер для обработки. Я знаю, что вы можете использовать https, но большинство браузеров по-прежнему отображают исходящие данные, что позволяет пользователю легко подделать запрос. Вот почему я хочу, чтобы пользователь видел запрос страницы, но не смог прочитать данные без расшифровки.
К сожалению для меня, документация по библиотеке as3crypto практически не существует, кроме комментариев в коде (которые не слишком помогают). Я настроил флэш-сторону вещей с парой статических функций, чтобы "реализовать" шифрование as3crypto blowfish, и они прекрасно работают для шифрования / дешифрования только во флэш-памяти. Проблема возникает, когда я пытаюсь использовать ключ для расшифровки в PHP с использованием библиотеки mcrypt. Вывод, который я получаю, не является исходным кодом, и я потратил пару дней, пытаясь понять, почему безрезультатно.
Ниже приведен код и пояснения. Для целей этого примера используемый ключ был "mykey" (без кавычек), а закодированные данные были "Hello World" (снова без кавычек).
Флэш-код (as3crypto blowfish helper):
package lib.ef.crypto
{
import com.hurlant.util.Base64;
import com.hurlant.crypto.Crypto;
import flash.utils.ByteArray;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.NullPad;
public class Blowfish
{
/**
* Encrypts a string.
* @param text The text string to encrypt.
* @param key A cipher key to encrypt the text with.
*/
static public function encrypt($text:String, $key:String=""):String
{
var cryptKey:ByteArray = new ByteArray();
cryptKey.writeUTF( $key );
var iPad:IPad = new NullPad();
var crypt:ICipher = Crypto.getCipher('blowfish-cfb',cryptKey,iPad);
iPad.setBlockSize( crypt.getBlockSize() );
var cryptText:ByteArray = new ByteArray();
cryptText.writeUTF( $text );
crypt.encrypt( cryptText );
trace( Base64.encodeByteArray( cryptText ) );
return null;
}
static public function decrypt($text:String, $key:String=""):String
{
return new String();
}
}
}
Вывод этого варьируется от прогона к прогону, но для целей этого примера прогона, я получаю закодированный в base64 вывод: 'EkKo9htSJUnzBmxc0A=='
Когда я переношу этот код в PHP, он будет декодирован с помощью base64, а затем передан в метод ниже для его расшифровки:
public static function decrypt($crypttext,$key)
{
if( !function_exists('mcrypt_module_open') ) trigger_error('The blowfish encryption class requires the Mcrypt library to be compiled into PHP.');
$plaintext = '';
$td = mcrypt_module_open('blowfish', '', 'cfb', '');
$blocksize = mcrypt_enc_get_block_size($td);
$iv = substr($crypttext, 0, $blocksize);
$crypttext = substr($crypttext, $blocksize);
if (true)
{
mcrypt_generic_init($td, $key, $iv);
$plaintext = mdecrypt_generic($td, $crypttext);
}
return $plaintext;
}
На данный момент вывод совершенно не читается. Я подозреваю, что проблема может быть связана с тем, что либо реализация blowfish as3crypto неверна (маловероятно), либо это может быть связано с тем, какое заполнение он использует (в настоящее время - нулевое заполнение), или, наконец, я думал, что это может иметь что-то делать со случайно сгенерированным вектором инициализации в as3crypto, который не добавляется к началу кодированной строки? Последний, который я не смог протестировать, потому что библиотека as3crypto большая, сложная и совсем не документирована. Я погуглил эту проблему и проверил все в течение пары дней, и я просто продолжаю придумывать непригодные данные в PHP. Я знаю, что если я смогу заставить работать систему Flash to PHP, я могу перепроектировать ее и запустить шифрование PHP to Flash.
Я приветствую весь вклад в этом вопросе, поскольку это фактически стоило мне спать по ночам LOL Спасибо заранее:)
Сегодня я провел дополнительное тестирование и попытался выяснить, был ли это вектор инициализации, как я и подозревал. Я не верю, что это проблема. Я изменил некоторые вещи во флэш-памяти, чтобы получить выход IV, использованный для генерации закодированного вывода:
package lib.ef.crypto
{
import com.hurlant.util.Base64;
import com.hurlant.crypto.Crypto;
import flash.utils.ByteArray;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.NullPad;
public class Blowfish
{
/**
* Encrypts a string.
* @param text The text string to encrypt.
* @param key A cipher key to encrypt the text with.
*/
static public function encrypt($text:String, $key:String=""):String
{
var cryptKey:ByteArray = new ByteArray();
cryptKey.writeUTF( $key );
var iPad:IPad = new NullPad();
var crypt = Crypto.getCipher('blowfish-cfb',cryptKey,iPad);
iPad.setBlockSize( crypt.getBlockSize() );
var cryptText:ByteArray = new ByteArray();
cryptText.writeUTF( $text );
crypt.encrypt( cryptText );
cryptText.position = 0;
var iv:ByteArray = crypt.IV;
iv.position = 0;
trace( Base64.encodeByteArray( iv ) );
trace( Base64.encodeByteArray( cryptText ) );
return null;
}
static public function decrypt($text:String, $key:String=""):String
{
return new String();
}
}
}
Для этого примера я получил закодированный IV '1bcGpqIbWRc=' и закодировал зашифрованные данные 'XpgART3hNQO10vcgLA=='. Я подключил их в модифицированную функцию PHP после base64_decode() их:
public static function decrypt($crypttext,$key,$iv=NULL)
{
if( !function_exists('mcrypt_module_open') ) trigger_error('The blowfish encryption class requires the Mcrypt library to be compiled into PHP.');
$plaintext = '';
$td = mcrypt_module_open('blowfish', '', 'cfb', '');
if( $iv === NULL ){
$ivsize = mcrypt_enc_get_iv_size($td);
echo '<pre>'.$ivsize.'</pre>';
$iv = substr($crypttext, 0, $ivsize);
echo '<pre>'.strlen($iv).'</pre>';
$crypttext = substr($crypttext, $ivsize);
}
if ($iv)
{
mcrypt_generic_init($td, $key, $iv);
$plaintext = mdecrypt_generic($td, $crypttext);
}
return $plaintext;
}
Даже этот вывод неверен. Я провел несколько тестов, чтобы убедиться, что IV соответствует нужному размеру как во flash, так и в PHP, но по какой-то причине сторона PHP просто не может расшифровать закодированный вывод blowfish из Flash. Я попытался использовать заполнение NULL и PKCS5 в as3crypto, и ни один из них не работает с системой PHP. Я проверил, чтобы убедиться, что строки IV одинаковы как во Flash, так и в PHP. Они оба используют одни и те же ключи. Оба используют режим CFB. Я не понимаю Тот же алгоритм, тот же ключ, тот же IV, тот же режим, но они не могут расшифровать друг друга. Мне кажется, что реализация blowfish as3crypto может быть неправильной. Кто-нибудь может это подтвердить?
2 ответа
После того, как я покопался в файлах библиотеки as3Crypto и демонстрационном коде, я обнаружил, что проблема в том, что мне нужно использовать функцию getCipher с режимом simple-blowfish-cfb вместо режима blowfish-cfb. Зашифрованный вывод из вызова crypt.encyrpt( cryptText) будет уже иметь префикс IV алгоритма, так что вы делаете один вызов Base64.encodeByteArray( cryptText), чтобы получить выходные данные для отправки в PHP. Когда вы инициализируете PHP, как я описал выше, он отрежет IV от строки и расшифрует его должным образом. Надеюсь, это поможет любому, кто придет с этой проблемой.
"Правильный" flash и PHP-код * приведен ниже для всех вас, TLDR, для тех, кому просто нужно быстрое решение для копирования / вставки: P
* Примечание: мне пришлось удалить некоторые из вызовов, специфичных для моего приложения, в обоих примерах кода, и я не проверял их, чтобы убедиться, что они функционируют на 100%, но они должны достаточно проиллюстрировать концепцию / структуру, чтобы, если они не работают должным образом, из коробки "вы можете легко исправить их для вашего использования.
PHP "вспомогательный" класс:
class Blowfish
{
public static function encrypt($plaintext,$key)
{
if( !function_exists('mcrypt_module_open') ) trigger_error('The blowfish encryption class requires the Mcrypt library to be compiled into PHP.');
$td = mcrypt_module_open('blowfish', '', 'cbc', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$crypttext = mcrypt_generic($td, $plaintext);
mcrypt_generic_deinit($td);
$out = $iv.$crypttext;
return $out;
}
public static function decrypt($crypttext,$key)
{
if( !function_exists('mcrypt_module_open') ) trigger_error('The blowfish encryption class requires the Mcrypt library to be compiled into PHP.');
$plaintext = '';
$td = mcrypt_module_open('blowfish', '', 'cbc', '');
$ivsize = mcrypt_enc_get_iv_size($td);
$iv = substr($crypttext, 0, $ivsize);
$crypttext = substr($crypttext, $ivsize);
if ($iv)
{
mcrypt_generic_init($td, $key, $iv);
$plaintext = mdecrypt_generic($td, $crypttext);
}
return $plaintext;
}
}
Флэш-класс "помощник":
package [your package name]
{
import com.hurlant.util.Base64;
import com.hurlant.util.Hex;
import com.hurlant.crypto.Crypto;
import flash.utils.ByteArray;
import com.hurlant.crypto.symmetric.IPad;
import com.hurlant.crypto.symmetric.ICipher;
import com.hurlant.crypto.symmetric.IVMode;
import com.hurlant.crypto.symmetric.NullPad;
public class Blowfish
{
/**
* Encrypts a string.
* @param txt The text string to encrypt.
* @param k A cipher key to encrypt the text with.
*/
static public function encrypt(txt:String, k:String=""):String
{
var kdata:ByteArray;
kdata = Hex.toArray(Hex.fromString(k));
var data:ByteArray;
data = Hex.toArray(Hex.fromString(txt));
var pad:IPad = new NullPad;
var mode:ICipher = Crypto.getCipher('simple-blowfish-cbc', kdata, pad);
pad.setBlockSize(mode.getBlockSize());
mode.encrypt(data);
return Base64.encodeByteArray( data );
}
/**
* Decrypts a string.
* @param txt The text string to decrypt.
* @param k A cipher key to decrypt the text with.
*/
static public function decrypt(txt:String, k:String=""):String
{
var kdata:ByteArray;
kdata = Hex.toArray(Hex.fromString( Base64.decode( k ) ));
var data:ByteArray;
data = Hex.toArray(Hex.fromString(txt));
var pad:IPad = new NullPad;
var mode:ICipher = Crypto.getCipher('simple-blowfish-cbc', kdata, pad);
pad.setBlockSize(mode.getBlockSize());
mode.decrypt(data);
data.position = 0;
return data.readUTFBytes( data.bytesAvailable );
}
}
}
Thanx! Смотрите здесь правильный "расшифровать":
static public function decrypt(txt:String, k:String=""):String{
var kdata:ByteArray;
kdata = Hex.toArray(Hex.fromString(k));
var data:ByteArray;
data = Base64.decodeToByteArray(txt);
var pad:IPad = new NullPad;
var mode:ICipher = Crypto.getCipher('simple-blowfish-cbc', kdata, pad);
pad.setBlockSize(mode.getBlockSize());
mode.decrypt(data);
data.position = 0;
return data.readUTFBytes( data.bytesAvailable );
}