0

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

对我来说不幸的是,除了代码中的注释(没有太大帮助)之外,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();
        }

    }
}

对于这个例子,我得到了一个 '1bcGpqIbWRc=' 的编码 IV 和 '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 实现可能不正确。谁能证实这一点?

4

2 回答 2

1

在对 as3Crypto 库文件和演示代码进行了一些挖掘之后,我发现问题是我需要将 getCipher 函数与 simple-blowfish-cfb 模式一起使用,而不是使用 blowfish-cfb 模式。调用 crypt.encyrpt( cryptText ) 的加密输出将已经以算法的 IV 为前缀,因此您只需调用 Base64.encodeByteArray( cryptText ) 即可将输出发送到 PHP。当您按照我上面的方式初始化 PHP 时,它会从字符串中切出 IV 并正确解密。希望这可以帮助其他遇到此问题的人。

“正确”的 Flash 和 PHP 代码* 在下面,供所有 TLDR 的人使用;那些只想快速复制/粘贴解决方案的人:P

*注意:我必须在两个代码示例中删除我的一些应用程序特定调用,并且没有测试它们以确保它们 100% 正常运行,但它们应该足以说明概念/结构,如果它们不能正常工作“out”盒子”,您可以轻松修补它们以供您使用。

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

    }
}
于 2011-08-10T13:35:29.170 回答
1

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

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

}
于 2013-03-10T15:36:48.577 回答