AES-256 CBC在php中加密并在Java中解密,反之亦然

JAVA

import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Base64; class AES256JavaPhp{ public static void main(String[] args) throws Exception { Base64 base64 = new Base64(); Cipher ciper = Cipher.getInstance("AES/CBC/PKCS5Padding"); SecretKeySpec key = new SecretKeySpec("PasswordPassword".getBytes("UTF-8"),"AES"); IvParameterSpec iv = new IvParameterSpec ("dynamic@dynamic@".getBytes("UTF-8"),0,ciper.getBlockSize()); //Encrypt ciper.init(Cipher.ENCRYPT_MODE, key,iv); byte[] encryptedCiperBytes = base64.encode ((ciper.doFinal("Hello".getBytes()))); System.out.println("Ciper : "+new String(encryptedCiperBytes)); //Decrypt ciper.init(Cipher.DECRYPT_MODE, key,iv); byte[] text = ciper.doFinal(base64.decode(encryptedCiperBytes)); System.out.println("Decrypt text : "+new String(text)); } } 

Java输出:

 Ciper : KpgzpzCRU7mTKZePpPlEvA== Decrypt text : Hello 

PHP

  $cipherText = encrypt("Hello", 'aes-256-cbc'); exit(); function encrypt($data, $algo) { $key = 'PasswordPassword'; //$iv = random_bytes(openssl_cipher_iv_length($algo)); $iv = 'dynamic@dynamic@'; $cipherText = openssl_encrypt( $data, $algo, $key, OPENSSL_RAW_DATA, $iv ); $cipherText = base64_encode($cipherText); printData("Ciper Text : $cipherText"); $cipherText = base64_decode($cipherText); $plaintext = openssl_decrypt( $cipherText, $algo, $key, OPENSSL_RAW_DATA, $iv ); printData("Plain Text after decryption : $plaintext"); } function printData($obj) { print_r($obj); } ?> 

PHP输出:

 Ciper Text : ef/ENVlBn9QBFlkvoN7P2Q== Plain Text after decryption : Hello 

得到的密码是不同的,即使它们使用相同的密钥和IV。 这怎么可能?

显然,您必须使用相同的AES密钥和IV来进行安全会话。 并且必须在客户之间妥善安全地进行沟通。 根本不管客户端写什么语言都没关系 。你的问题不是理解密钥协议和会话建立的协议。

初始化向量不是受保护的值; 即,在客户端之间进行通信时,您不会对其进行加密。 它必须使用加密的AES密钥(您从某些密钥协商协议派生) 以明文forms打包。

CMS使用KeyTransRecipientInfo来提供此信息。 TLS还定义IV建立跟随其握手 。 我强烈建议遵循CMS实现,而不是设计的东西,几乎保证包含安全漏洞。


更新

现在很清楚,你很困惑为什么最终的密文不是确定性的。 这是因为Java实现默认为128位加密并且提供了128位密钥, PHP代码请求256位强度加密并且仅提供相同的128位密钥 。 因此,PHP必须填充密钥。


更新2

根据您的以下注释,以下是使用Java生成256位密钥的示例:

 KeyGenerator generator = KeyGenerator.getInstance("AES"); generator.init(256); // The AES key size in number of bits SecretKey secKey = generator.generateKey(); 

您的密钥只有128位(16字节)长,但您在PHP中请求AES-256。 这将导致填充的AES密钥为256位(32字节)。 您必须要求AES-128才能使用。 这就是OpenSSL扩展在PHP中的工作方式。

理想情况下,键应该看起来像随机噪音,以防止暴力攻击。 你当前的钥匙不是那个。 这是非常可预测的。 您应该生成一些随机密钥,并以编码forms将其添加到您的代码中,如Base64。 然后你可以在使用前解码它。