昨天有人在群里问了一个问题,就是某平台加密是用的Java aes加密的,现在需要在php解密,因为他并不熟悉php,所以在群里求助,java的代码如下:
要想实现这个加密解密,就必须先知道Java这个默认的aes加密的模式是什么。这个在网上搜一下告知是AES / ECB / PKCS5Padding
其实我最开始直接搜到php实现java默认aes加密,就发现了一段代码
<?php
class Security
{
public static function encrypt($input, $key)
{
$size = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$input = Security::pkcs5_pad($input, $size);
$td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$data = base64_encode($data);
return $data;
}
private static function pkcs5_pad($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
public static function decrypt($sStr, $sKey)
{
$decrypted = mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
$sKey,
base64_decode($sStr),
MCRYPT_MODE_ECB
);
$dec_s = strlen($decrypted);
$padding = ord($decrypted[$dec_s - 1]);
$decrypted = substr($decrypted, 0, -$padding);
return $decrypted;
}
}
$key = "vNh4KDg8fWhbRrtQd7n3OQ==";
$data = "isy4hRbptvsBl42JAkIbY6uA/TiiHQQr1Aj3HMEezCs=";
echo "解密字符串:" . Security::ssl_decrypt($data, base64_decode($key));
运行了一下,发现是可行的,但是php7.1后,mcrypt_
系列函数就被警告或移除了,所以需要将其改成openssl系列函数,但恰恰在改成openssl的过程中,走了很多弯路。
我开始没有注意ECB
模式,一直尝试的是CBC
然后一直纠结于iv的值是多少,试了各种方法,比如
$cipher = 'aes-128-cbc';
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher));
或者
$zeroPack = pack('i*', 0);
$iv = str_repeat($zeroPack, 4);
$iv=substr($key . '0000000000000000', 0, 16);
总之尝遍了网上的各种办法,但依旧不好使。
后来又怀疑是不是对齐方式有问题,毕竟openssl默认的对齐方式是PKCS7,于是又试图通过pkcs5填充后再加密,但还是不行。
后面几乎就是各种方案的排列组合了,但是一番折腾下来,一个小时还没搞定。
直到要放弃的时候,扫了眼AES / ECB / PKCS5Padding
然后对比下我用的aes-128-cbc
,突然发现一个是ecb一个是cbc,以后查了下区别。
在CBC模式中,首先将明文分组与前一个密文分组进行XOR运算,然后再进行加密。
CBC模式加解密过程如下:
可以看到的是ecb根本没有XOR运算这一步,所以根本不需要初始化向量iv.
所以,最终的代码异常简单
$key = "vNh4KDg8fWhbRrtQd7n3OQ==";
$data = "isy4hRbptvsBl42JAkIbY6uA/TiiHQQr1Aj3HMEezCs=";
$s = openssl_decrypt(base64_decode($data), 'AES-128-ECB', base64_decode($key), OPENSSL_RAW_DATA);
echo "解密字符串:" . $s,"\n";