以下 JS 和 Perl 程序使用相同的数据进行加密,但产生不同的结果。他们不应该产生相同的输出吗?

问题描述 投票:0回答:1

以下程序,一个用 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]
javascript perl encryption
1个回答
0
投票

感谢 @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;
}
© www.soinside.com 2019 - 2024. All rights reserved.