第三方 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_generic
和 mcrypt_encrypt
这两种实现,但结果和 openssl_encrypt
一模一样
求大大指教
补充一下 mcrypt_encrypt
和 mcrypt_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);
}
1
fcicq 2016-06-14 14:16:03 +08:00 1
php 版 iv 的 '0' 其实是 0x30 吧. 不会写字符串吗?
|
3
Sunyanzi 2016-06-14 14:52:26 +08:00 2
$iv = str_repeat( chr( 0 ), 16 );
一楼已经说得很明白了 ... 我补一句 ... 这是个空白 IV ... 意思是使用 CBC 但不使用初始化向量 ... 这么做就把 CBC 的安全级降到和 ECB 一样了 ... 所以你在程序里直接使用 ECB 加密是正确的 ... |
5
timsims OP @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 }); |
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); } |