【问题标题】:Errors decrypting as3crypto blowfish data in PHP在 PHP 中解密 as3crypto 河豚数据时出错
【发布时间】:2016-06-06 16:11:12
【问题描述】:

我现在对 ActionScript 3 有点陌生,我一直在尝试使用 as3crypto 库通过河豚算法对一些数据进行加密,然后再将其提交给服务器进行处理。我知道您可以使用 https,但大多数浏览器仍会显示出站数据,这使得用户很容易伪造请求。这就是为什么我想让用户看到页面请求,但不解密就无法读取数据。

对我来说不幸的是,除了代码中的 cmets(没有太大帮助)之外,as3crypto 库上的 deocumentation 几乎不存在。我已经用几个静态函数设置了闪存方面的东西来“实现”as3crypto河豚加密,它们只能在闪存内加密/解密。当我尝试使用密钥在 PHP 中使用 mcrypt 库进行解密时,问题就出现了。我得到的输出不是原始代码,我花了几天时间试图弄清楚为什么无济于事。

下面是代码和解释。在本示例中,使用的密钥是“mykey”(不带引号),编码数据是“Hello World”(同样不带引号)。

Flash 代码(as3crypto 河豚助手):

    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;
}

此时输出完全不可读。我怀疑这个问题可能与河豚的 as3crypto 实现不正确(不太可能)或者它可能与它使用的填充(当前为空填充)有关,或者最后我认为它可能有与 as3crypto 中随机生成的初始化向量没有被添加到编码字符串的前面有关吗?最后一个我无法真正测试,因为 as3crypto 库很大、很复杂,而且根本没有太多文档记录。我已经用谷歌搜索了这个问题并测试了几天所有的东西,我只是不断地想出 PHP 中不可用的数据。我知道如果我可以让 Flash 到 PHP 系统正常工作,我可以对其进行逆向工程以使 PHP 到 Flash 加密也运行。

我欢迎所有关于这个问题的意见,因为它实际上让我晚上睡不着,哈哈,提前谢谢你:)


我今天做了一些进一步的测试,并试图看看它是否是我怀疑的初始化向量。我不相信这是问题所在。我在 flash 中修改了一些东西,以便获得用于生成编码输出的 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==' 我在 base64_decode() 之后将它们插入到修改后的 PHP 函数中:

 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 方面无法解密来自 Flash 的河豚编码输出。我尝试在 as3crypto 中同时使用 NULL 和 PKCS5 填充,但它们都不适用于 PHP 的系统。我已经测试以确保 IV 字符串在 Flash 和 PHP 中是相同的。他们都使用相同的密钥。两者都使用CFB模式。我不明白。相同的算法,相同的密钥,相同的 IV,相同的模式,但它们不能相互解密。在我看来,河豚的 as3crypto 实现可能不正确。谁能证实这一点?

【问题讨论】:

    标签: php flash encryption blowfish as3crypto


    【解决方案1】:

    在对 as3Crypto 库文件和演示代码进行了一些挖掘之后,我发现问题是我需要在 simple-blowfish-cfb 模式下使用 getCipher 函数,而不是使用 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;
        }
    
    }
    

    Flash“助手”类:

    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 );
            }
    
        }
    }
    

    【讨论】:

    • 顺便说一句,如今的加密标准是 AES 加密。通常最好符合标准。
    【解决方案2】:

    谢谢! 在这里查看正确的“解密”:

    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 );
    
    }
    

    【讨论】:

      猜你喜欢
      • 2012-04-02
      • 2016-02-29
      • 1970-01-01
      • 2018-09-07
      • 1970-01-01
      • 1970-01-01
      • 2014-04-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多