V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
timsims
V2EX  ›  程序员

如何把以下 java AES-128-CBC 加密方法改为 php 的实现

  •  
  •   timsims · 2016-06-14 13:58:15 +08:00 · 4786 次点击
    这是一个创建于 3084 天前的主题,其中的信息可能已经有所发展或是发生改变。

    第三方 API 需要用到的加密,他们就一个 java demo ,需要自己改为 php 来实现,但我试了好久都没办法得到相同的结果

    Java 的源码

    public static String encrypt(String input, String key){
        byte[] crypted = null;
    
        SecretKeySpec skey = new SecretKeySpec(getHash("MD5", key), "AES");
        IvParameterSpec iv = new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, skey, iv);
        crypted = cipher.doFinal(input.getBytes());
        return new String(Base64.encodeBase64(crypted));
    }
    
     private static byte[] getHash(String algorithm, String text) {
        try {
            byte[] bytes = text.getBytes("UTF-8");
            final MessageDigest digest = MessageDigest.getInstance(algorithm);
            digest.update(bytes);
            return digest.digest();
        } catch (final Exception ex) {
            throw new RuntimeException(ex.getMessage());
        }
    }
    

    我自己做 PHP 的实现

    public static function encrypt($input, $key) {
    
        $key = hash('md5', $key, true);
        $iv = '0000000000000000';
        return openssl_encrypt($input, 'aes-128-cbc', $key, 0, $iv);
    }
    

    结果

    key:"790757e76c8942f995675b247aa57c2a"
    input:"1234"
    
    result in java:UfczMtIAm8ewSuIGRdPTDQ==
    result in PHP:wd/OTHoIXwgHGDHcj8OTgg== 
    

    如果换成把 cipher 方法换成 ECB 结果就相同了。。

    我还试过 mcrypt_genericmcrypt_encrypt 这两种实现,但结果和 openssl_encrypt 一模一样

    求大大指教

    第 1 条附言  ·  2016-06-14 14:50:46 +08:00

    补充一下 mcrypt_encryptmcrypt_generic 的实现,结果都是一样的。。

    public static function encrypt($input, $key) {
    
        $key = hash('md5', $key, true);
    
    
        $iv = '0000000000000000';
    
        $size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
        $input = Security::pkcs5_pad($input, $size);
    
    
        $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $input, MCRYPT_MODE_CBC, $iv);
    
        // output wd/OTHoIXwgHGDHcj8OTgg==
        echo base64_encode($encrypted);
    
        $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');
    
        mcrypt_generic_init($td, $key, $iv);
        $data = mcrypt_generic($td, $input);
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td);
        $data = base64_encode($data);
    
        // output wd/OTHoIXwgHGDHcj8OTgg==
        echo $data;
    }
    
    private static function pkcs5_pad ($text, $blocksize) {
        $pad = $blocksize - (strlen($text) % $blocksize);
        return $text . str_repeat(chr($pad), $pad);
    }
    
    
    6 条回复    2016-06-15 09:03:45 +08:00
    fcicq
        1
    fcicq  
       2016-06-14 14:16:03 +08:00   ❤️ 1
    php 版 iv 的 '0' 其实是 0x30 吧. 不会写字符串吗?
    timsims
        2
    timsims  
    OP
       2016-06-14 14:24:17 +08:00
    @fcicq 没看懂你的意思。。
    Sunyanzi
        3
    Sunyanzi  
       2016-06-14 14:52:26 +08:00   ❤️ 2
    $iv = str_repeat( chr( 0 ), 16 );

    一楼已经说得很明白了 ... 我补一句 ... 这是个空白 IV ... 意思是使用 CBC 但不使用初始化向量 ...

    这么做就把 CBC 的安全级降到和 ECB 一样了 ... 所以你在程序里直接使用 ECB 加密是正确的 ...
    wzxjohn
        4
    wzxjohn  
       2016-06-14 14:56:41 +08:00   ❤️ 1
    @timsims 你需要理解全是 0 的字符串和全是 0 的 Byte 数组的区别。。。
    timsims
        5
    timsims  
    OP
       2016-06-14 14:58:02 +08:00
    @Sunyanzi 懂了。。。

    $iv = '0000000000000000';

    我是找网上的例子,他们还特意注释 ``` // iv same as java ````, 我一直以为 16 个 0 就相当于 Java 那段 new IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
    liumw
        6
    liumw  
       2016-06-15 09:03:45 +08:00
    给个参考

    function AES_PKCS5_ENCRYPT($text, $key)
    {
    $alg = MCRYPT_RIJNDAEL_128;
    $mode = MCRYPT_MODE_ECB;
    $iv_size = mcrypt_get_iv_size($alg, $mode);
    $block_size = mcrypt_get_block_size($alg, $mode);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);
    $this->iv = $iv;
    $input = $this->pkcs5_pad($text, $block_size);
    $crypttext = mcrypt_encrypt($alg, $key, $input, $mode, $iv);
    return base64_encode($crypttext);
    }

    function AES_PKCS5_DECRYPT($text, $key)
    {
    $alg = MCRYPT_RIJNDAEL_128;
    $mode = MCRYPT_MODE_ECB;
    $text = base64_decode($text);
    $decrypted = mcrypt_decrypt($alg, $key, $text, $mode, $this->iv);
    $decrypted = $this->pkcs5_unpad($decrypted);
    return $decrypted;
    }


    function pkcs5_pad($text, $blocksize)
    {
    $pad = $blocksize - (strlen($text) % $blocksize);
    return $text . str_repeat(chr($pad), $pad);
    }

    function pkcs5_unpad($text)
    {
    $pad = ord($text{strlen($text) - 1});
    if ($pad > strlen($text)) return false;
    if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) return false;
    return substr($text, 0, -1 * $pad);
    }
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1321 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 17:44 · PVG 01:44 · LAX 09:44 · JFK 12:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.