You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 09:27:56