TL;DR - 尝试使用 32 字节密钥而不是 16 字节密钥。
在撰写了早期答案并最终将其删除后,反驳了我自己关于这是填充问题的理论:-),我现在相当确定问题可能只是与密钥长度有关。
在尝试重现您的问题时,我无法使第一个密文块在使用生成时相同openssl_encrypt
vs CryptoJS
。然后我把钥匙的长度加倍,它就起作用了。
上面生成的密钥是 32 个字符,但转换后只有 16 个字节,因此请尝试将其加倍,看看会发生什么。
FWIW,这是我用来测试密钥长度的 PHP 代码:
$data = "hello! this is a test!";
$method = 'aes-256-cbc';
$key = '59b6ab46d379b89d794c87b74a511fbd59b6ab46d379b89d794c87b74a511fbd';
$iv = '0aaff094b6dc29742cc98a4bac8bc8f9';
$e = openssl_encrypt( $data, $method, hex2bin( $key ), 0, hex2bin( $iv ));
echo 'Ciphertext: [', bin2hex( base64_decode( $e )), "]\n";
echo 'Key: [', $key, "]\n";
echo 'Cleartext: [', openssl_decrypt( $e, $method, hex2bin( $key ), 0, hex2bin( $iv )), "]\n";
// Test with openssl on the command line as well, just to be sure!
file_put_contents( 'clear.txt', $data );
$exec = "openssl enc -$method -e -in clear.txt -out encrypted.txt -base64 -nosalt -K $key -iv $iv";
exec ($exec);
$out = file_get_contents( 'encrypted.txt' );
echo 'Ciphertext: [', bin2hex( base64_decode(trim($out))), "]\n";
这是兼容的 JavaScript,我使用它运行jsc
在我的 Mac 上:
var data = "hello! this is a test!";
var key = '59b6ab46d379b89d794c87b74a511fbd59b6ab46d379b89d794c87b74a511fbd';
var iv = '0aaff094b6dc29742cc98a4bac8bc8f9';
var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(data), CryptoJS.enc.Hex.parse(key), { iv: CryptoJS.enc.Hex.parse(iv) });
print( 'Ciphertext: [' + encrypted.ciphertext + ']' );
print( 'Key: [' + encrypted.key + ']' );
cipherParams = CryptoJS.lib.CipherParams.create({ciphertext: CryptoJS.enc.Hex.parse(encrypted.ciphertext.toString())});
var decrypted = CryptoJS.AES.decrypt(cipherParams, CryptoJS.enc.Hex.parse(key), { iv: CryptoJS.enc.Hex.parse(iv) });
print( 'Cleartext: [' + decrypted.toString(CryptoJS.enc.Utf8) + ']');
无论输入的长度如何,这两段代码都会生成相同的密文,这证实了两个库之间的填充策略是兼容的。但是,如果将密钥长度减半,密文将不再相同,这显然意味着解密也将不兼容。
UPDATE
我刚刚发现hash_pbkdf2()
默认返回 ASCII 十六进制字符串,因此您应该转换$encryptHash
到二进制hex2bin()
在将其传递给之前openssl_encrypt()
或设置最后一个参数hash_pbkdf2()
to true
获得原始输出。
UPDATE 2
我刚刚确认,如果您进行以下更改,您的代码将有效:
在 PHP 中,将密钥大小从 32 字节更改为 64 字节,并在生成密钥时添加原始输出选项:
$encryptHash = hash_pbkdf2("sha256", "0000", "secret", 1000, 64, 1);
在 JavaScript 中将密钥长度从 128 位更改为 256 位:
var key256Bits = CryptoJS.PBKDF2("0000", "secret", { keySize: 256/32, iterations: 1000, hasher: CryptoJS.algo.SHA256 });
希望这些改变在您尝试时能够发挥作用。