Ошибки дешифрования данных 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 );

}
Другие вопросы по тегам