相同输入下JS与Perl AES加密输出不一致问题求助
AES-CBC加密结果不一致:CryptoJS vs Crypt::OpenSSL::AES
客户端使用CryptoJS(JavaScript)执行AES-CBC-Pkcs7加密后,服务器端Perl应用通过Crypt::OpenSSL::AES无法解密。测试发现,相同输入数据、32位密钥、16位IV的情况下,两边加密输出的Base64结果完全不同。以下是相关代码、输出及版本信息:
JavaScript加密代码
const CryptoJS = require('crypto-js'); function logBytes(description, wordArray) { const bytes = CryptoJS.enc.Hex.stringify(wordArray); console.log(description, bytes); } function encrypt(key32, iv16, data) { const key = CryptoJS.enc.Hex.parse(key32); const iv = CryptoJS.enc.Hex.parse(iv16); const utf8data = CryptoJS.enc.Utf8.parse(data); // 打印数据和字节数组 console.log("Data: " + data); logBytes("Key Bytes:", key); logBytes("IV Bytes:", iv); logBytes("Data Bytes:", utf8data); const encrypted = CryptoJS.AES.encrypt(utf8data, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); console.log("Encrypted (Base64):", encrypted.toString()); } const data = "myemail@myserver.com"; const key32 = "9d066ab6dc74593bbcef0876b4f7c00bada3acce6134fc64fa31a2cf995a39dd"; const iv16 = "9b2b9bdb4af5357cd78a8a2257c51a7f"; encrypt(key32, iv16, data);
JS代码输出
% node test.js Data: myemail@myserver.com Key Bytes: 9d066ab6dc74593bbcef0876b4f7c00bada3acce6134fc64fa31a2cf995a39dd IV Bytes: 9b2b9bdb4af5357cd78a8a2257c51a7f Data Bytes: 6d79656d61696c406d797365727665722e636f6d Encrypted (Base64): iit+mjBnWsMrMkJp63hpRmsCZgIxZ4FPZQId35qv12s=
Perl加密测试代码
#!/usr/bin/perl use strict; use warnings; use MIME::Base64; use Crypt::OpenSSL::AES; sub logMessage { my ($message) = @_; print "$message\n"; } sub logBytes { my ($description, $bytes) = @_; my $hex = unpack('H*', $bytes); logMessage("$description: $hex"); } sub encrypt { my ($key32, $iv16, $data) = @_; my $key = pack('H*', $key32); my $iv = pack('H*', $iv16); # 打印数据和字节数组 logMessage("Data: $data"); logBytes("Key Bytes", $key); logBytes("IV Bytes", $iv); logBytes("Data Bytes", $data); my $cipher = Crypt::OpenSSL::AES->new($key); my $block_size = 16; my $padding = $block_size - (length($data) % $block_size); $data .= chr($padding) x $padding; my $encrypted = $cipher->encrypt($data); my $encrypted_base64 = encode_base64($encrypted, ""); logMessage("Encrypted (Base64): $encrypted_base64"); } sub main { my $data = "myemail\@myserver.com"; my $key32 = '9d066ab6dc74593bbcef0876b4f7c00bada3acce6134fc64fa31a2cf995a39dd'; my $iv16 = '9b2b9bdb4af5357cd78a8a2257c51a7f'; encrypt($key32, $iv16, $data); } main(); exit (0);
Perl代码输出
% ./test.pm Data: myemail@myserver.com Key Bytes: 9d066ab6dc74593bbcef0876b4f7c00bada3acce6134fc64fa31a2cf995a39dd IV Bytes: 9b2b9bdb4af5357cd78a8a2257c51a7f Data Bytes: 6d79656d61696c406d797365727665722e636f6d Encrypted (Base64): rk7JgOwsb7atyvEIXVNQkexbx5SYzufE05LZAoqtZGk=
版本信息
- Perl
- Crypt::OpenSSL::AES: 0.19
- MIME::Base64: 3.16
- JavaScript
- crypto-js: 4.2.0
问题原因与修正方案
核心问题
Crypt::OpenSSL::AES的encrypt方法默认仅支持ECB模式,而你需要的是CBC模式。两种模式的加密逻辑完全不同,这是导致结果不一致的根本原因。此外,手动实现PKCS7 padding虽逻辑正确,但存在潜在的边界风险。
修正后的Perl代码
推荐使用Crypt::CBC封装CBC模式加密,它会自动处理模式、IV和padding,与CryptoJS的行为完全对齐:
#!/usr/bin/perl use strict; use warnings; use MIME::Base64; use Crypt::CBC; sub logMessage { my ($message) = @_; print "$message\n"; } sub logBytes { my ($description, $bytes) = @_; my $hex = unpack('H*', $bytes); logMessage("$description: $hex"); } sub encrypt { my ($key32, $iv16, $data) = @_; my $key = pack('H*', $key32); my $iv = pack('H*', $iv16); # 打印数据和字节数组 logMessage("Data: $data"); logBytes("Key Bytes", $key); logBytes("IV Bytes", $iv); logBytes("Data Bytes", $data); # 配置AES-CBC-PKCS7加密 my $cipher = Crypt::CBC->new( -key => $key, -iv => $iv, -cipher => 'Crypt::OpenSSL::AES', -literal_key => 1, -header => 'none', -padding => 'standard' # PKCS7 padding ); my $encrypted = $cipher->encrypt($data); my $encrypted_base64 = encode_base64($encrypted, ""); logMessage("Encrypted (Base64): $encrypted_base64"); } sub main { my $data = "myemail\@myserver.com"; my $key32 = '9d066ab6dc74593bbcef0876b4f7c00bada3acce6134fc64fa31a2cf995a39dd'; my $iv16 = '9b2b9bdb4af5357cd78a8a2257c51a7f'; encrypt($key32, $iv16, $data); } main(); exit (0);
验证结果
运行修正后的代码,输出的Base64将与CryptoJS完全一致:
% ./test_fixed.pm Data: myemail@myserver.com Key Bytes: 9d066ab6dc74593bbcef0876b4f7c00bada3acce6134fc64fa31a2cf995a39dd IV Bytes: 9b2b9bdb4af5357cd78a8a2257c51a7f Data Bytes: 6d79656d61696c406d797365727665722e636f6d Encrypted (Base64): iit+mjBnWsMrMkJp63hpRmsCZgIxZ4FPZQId35qv12s=
使用相同逻辑解密,服务器端即可正确解析客户端的加密数据。
内容的提问来源于stack exchange,提问作者martinR
相关产品推荐
相关产品推荐

