以下程序,一个用 Javascript 编写,另一个用 Perl 编写,应该执行相同的任务,它们具有相同的输入数据。但是,输出是不同的。该问题源于客户端使用的 JS,向服务器端的应用程序发送 POST 请求,该请求是用 Perl 编写的。 Perl 程序未能解密,且原因不明。经过分析,我得出的结论是,使用两种不同编程语言的库的行为不同。所以我用 Perl 编写了客户端来证明这一点。结果如下。
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);
// Log data and byte arrays
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 = "[email protected]";
const key32 = "9d066ab6dc74593bbcef0876b4f7c00bada3acce6134fc64fa31a2cf995a39dd";
const iv16 = "9b2b9bdb4af5357cd78a8a2257c51a7f";
encrypt(key32, iv16, data);
输出:
% node test.js
Data: [email protected]
Key Bytes: 9d066ab6dc74593bbcef0876b4f7c00bada3acce6134fc64fa31a2cf995a39dd
IV Bytes: 9b2b9bdb4af5357cd78a8a2257c51a7f
Data Bytes: 6d79656d61696c406d797365727665722e636f6d
Encrypted (Base64): iit+mjBnWsMrMkJp63hpRmsCZgIxZ4FPZQId35qv12s=
#!/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);
# Log data and byte arrays
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);
输出
% ./test.pm
Data: [email protected]
Key Bytes: 9d066ab6dc74593bbcef0876b4f7c00bada3acce6134fc64fa31a2cf995a39dd
IV Bytes: 9b2b9bdb4af5357cd78a8a2257c51a7f
Data Bytes: 6d79656d61696c406d797365727665722e636f6d
Encrypted (Base64): rk7JgOwsb7atyvEIXVNQkexbx5SYzufE05LZAoqtZGk=
Versions:
Perl:
Crypt::OpenSSL::AES version: 0.19
MIME::Base64 version: 3.16
JS:
[email protected]
感谢 @Topaco 提供的线索,问题得到了解决 - 归功于他。
以下客户端JS和服务器端Perl是一个解决方案
const CryptoJS = require('crypto-js');
function encrypt(key_hex, iv_hex, data) {
const key = CryptoJS.enc.Hex.parse(key_hex);
const iv = CryptoJS.enc.Hex.parse(iv_hex);
const utf8data = CryptoJS.enc.Utf8.parse(data);
const encrypted = CryptoJS.AES.encrypt(utf8data, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
});
// Convert to base64 for easier transmission and compatibility with Perl's decode_base64
return encrypted.toString();
}
var key_hex = "9d066ab6dc74593bbcef0876b4f7c00bada3acce6134fc64fa31a2cf995a39dd";
var iv_hex = "9b2b9bdb4af5357cd78a8a2257c51a7f";
var data = process.argv[2];
const encryptedBase64 = encrypt(key_hex, iv_hex, data);
console.log(encryptedBase64);
use MIME::Base64;
use Crypt::CBC;
use strict;
sub decrypt_hex {
my ($key_hex, $iv_hex, $data) = @_;
# Convert hex key and IV to binary
my $key = pack("H*", $key_hex);
my $iv = pack("H*", $iv_hex);
# Set up the decryption cipher with CBC mode and Rijndael (AES)
my $cipher = Crypt::CBC->new(
-key => $key,
-cipher => 'Crypt::Rijndael',
-iv => $iv,
-header => 'none',
-keysize => 32, # Adjust according to your key length (16 for AES-128, 24 for AES-192, 32 for AES-256)
-literal_key => 1,
-padding => 'standard' # Ensures PKCS#7 padding is handled
);
# Decode the base64-encoded data
my $encrypted = decode_base64($data);
# Decrypt the data
my $decrypted = $cipher->decrypt($encrypted);
return $decrypted;
}