使用 PHP 获得与 java 相同的 AES-128-CBC 加密
Use PHP to get the same AES-128-CBC encryption as java does
我知道围绕 Whosebug 有很多关于 PHP Java AES CBC 加密的讨论,但是 none 解决了我的问题
这里是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==
在php中,我也有使用其他的方法,比如mcrypt_encrypt
,mcrypt_generic
加上pkcs5 padding(见代码blow),它们都可以得到相同的加密方式openssl_encrypt
做到了,但仍然与 Java 函数结果不一样
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);
}
我注意到另一件奇怪的事情,如果我将密码方法从 CBC 更改为 ECB,java 和 php 加密将是相同的,但遗憾的是访问第 3 方 API, 我必须使用 CBC
终于想通了
$iv = '0000000000000000';
应该替换为
$iv = str_repeat(chr(0), 16);
我从其他地方复制它并认为 '0000000000000000'
等于 IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })
,那是完全错误的..
我知道围绕 Whosebug 有很多关于 PHP Java AES CBC 加密的讨论,但是 none 解决了我的问题
这里是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==
在php中,我也有使用其他的方法,比如mcrypt_encrypt
,mcrypt_generic
加上pkcs5 padding(见代码blow),它们都可以得到相同的加密方式openssl_encrypt
做到了,但仍然与 Java 函数结果不一样
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);
}
我注意到另一件奇怪的事情,如果我将密码方法从 CBC 更改为 ECB,java 和 php 加密将是相同的,但遗憾的是访问第 3 方 API, 我必须使用 CBC
终于想通了
$iv = '0000000000000000';
应该替换为
$iv = str_repeat(chr(0), 16);
我从其他地方复制它并认为 '0000000000000000'
等于 IvParameterSpec(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 })
,那是完全错误的..