Javascript与Perl间AES加密解密无输出问题求助
问题解决:JavaScript AES加密后Perl解密无输出
问题背景
尝试从JavaScript向Perl发送AES加密的数据,但Perl端解密后无输出。预期Perl能正确解密JS加密的消息,以下是可复现的最简代码:
JavaScript 加密代码
var keySize = 256; var ivSize = 128; var iterations = 100; function testcrypt(){ var pass = 'testpass'; var msg = 'testmsg'; var salt = CryptoJS.lib.WordArray.random(128/8); var key = CryptoJS.PBKDF2(pass, salt, { keySize: keySize/32, iterations: iterations }); var iv = CryptoJS.lib.WordArray.random(128/8); var encrypted = CryptoJS.AES.encrypt(JSON.stringify(msg), key, { iv: iv, padding: CryptoJS.pad.Pkcs7, mode: CryptoJS.mode.CBC }); // salt, iv为十六进制字符串,拼接后用于解密 var packet = salt.toString()+'-'+ iv.toString()+'-' + encrypted.toString(); alert(packet); }
输出示例:71b851532027b022c50f1a389254fca4-d8a9d7c4fa30f7d9427a5762e2c5794b-8S/JOXgDYuRloLKBiH5fYg==
原Perl解密代码问题分析
原代码存在以下关键错误:
- 密钥长度配置错误:用密码字符串长度(
length $key)作为key_len,但CryptoJS生成的是256位(32字节)密钥,需显式指定key_len => 32 - 十六进制未解码:盐和IV是十六进制字符串,直接使用会导致PBKDF2生成错误密钥,需先解码为二进制
- Crypt::CBC初始化错误:无需指定
-pbkdf参数(已手动生成密钥),且未传入正确的IV值 - IV长度配置错误:用十六进制字符串长度(
length $iv)作为iv_len,实际IV是128位(16字节),需指定iv_len => 16
修正后的Perl解密代码
use warnings; use strict; use Crypt::CBC; use Crypt::PBKDF2; use MIME::Base64; use Digest::SHA qw(sha1); print "\nGot: ".decrypt('ebdfcbd226b7dbc73e77a29d31fab723-3daf178979cb03087f5258907e73e547-CyG6R0EU9s0c8dBCAZk6Jg==', 'testpass'); print "\nGot: ".decrypt('71b851532027b022c50f1a389254fca4-d8a9d7c4fa30f7d9427a5762e2c5794b-8S/JOXgDYuRloLKBiH5fYg==', 'testpass'); sub decrypt{ my ($encrypted, $pass) = @_; my ($salt_hex, $iv_hex, $packet_b64) = split '-', $encrypted, 3; # 解码十六进制的盐和IV为二进制 my $salt = pack('H*', $salt_hex); my $iv = pack('H*', $iv_hex); # 解码base64密文 my $ciphertext = decode_base64($packet_b64); # 配置PBKDF2,匹配CryptoJS参数:256位密钥,100迭代,HMAC-SHA1 my $pbkdf2 = Crypt::PBKDF2->new( hash_class => 'HMACSHA1', iterations => 100, output_len => 32, # 对应CryptoJS的256位密钥 ); # 生成密钥(注意参数顺序:Crypt::PBKDF2是(salt, pass),和CryptoJS相反) my $aes_key = $pbkdf2->PBKDF2($salt, $pass); # 初始化Crypt::CBC,指定密钥、IV、无头部、AES算法 my $cbc = Crypt::CBC->new( -key => $aes_key, -cipher => 'Cipher::AES', -iv => $iv, -header => 'none', -padding => 'standard', # PKCS7填充,和CryptoJS一致 -literal_key => 1, # 使用原始密钥,不做额外处理 ); # 解密并返回结果 return $cbc->decrypt($ciphertext); }
关键修正说明
- 用
pack('H*', $hex_str)将盐和IV的十六进制字符串转为二进制,确保PBKDF2生成正确的密钥 - 显式指定PBKDF2的
output_len => 32,对应CryptoJS的256位密钥规格 - Crypt::CBC初始化时传入正确的IV,启用
-literal_key => 1避免对密钥做额外加工 - 移除不必要的
-pbkdf参数,因为已手动用PBKDF2完成密钥派生
内容的提问来源于stack exchange,提问作者R M
相关产品推荐
相关产品推荐

