javascript - 使用 CryptoJS (JAVASCRIPT) 和 OpenSSL (PHP) 实现相同的加密

标签 javascript php encryption openssl cryptography

我想在 ReactJS 应用程序中实现 PhP 加密功能。我需要以使用 OpenSSL 库函数 (openssl_encrypt) 创建的特定格式发送 token 。

与 JAVASCRIPT 函数相比,PHP 函数生成的字符串短了几个字符。当然,两者都具有相同的属性。

PHP:

protected static function encrypt($stringData) {
  $encrypted = false;
  $encrypt_method = 'AES-256-CBC';
  $iv = substr(hash('sha256', static::$ivMessage), 0, 16);
  $encrypted= openssl_encrypt($stringData, $encrypt_method, static::$apiSecret, 0, $iv);

  return $encrypted;
}

JavaScript:

export const encrypt = (stringData) => {
  const iv = CryptoJS.SHA256(IV_MESSAGE).toString(CryptoJS.enc.Hex).substring(0, 16);
  const encrypted = CryptoJS.AES.encrypt(stringData, API_SECRET, {
    iv,
    mode: CryptoJS.mode.CBC,
    pad: CryptoJS.pad.ZeroPadding,
  });

  return encrypted;
};

示例常量:

const stringData = "{"uid":19,"price":10000000,"duration":240,"credit_purpose":5,"new_tab":false,"cssFile":"kalkulatorok","css":[],"supported":false,"email":"test@test.hu","productType":"home_loan","method":"calculator","calculatorType":"calculator","unique":true}";
const IV_MESSAGE = "a";
const API_SECRET = "secret_key"; 

(PHP 函数相同 --> $stringData, $ivMessage; $apiSecret)

如何实现在JAVASCRIPT 中“复制”PHP 函数?到目前为止我错过了什么?

最佳答案

CryptoJS 代码中的以下更改对于生成 PHP 代码的密文是必要的:

  • key 必须作为 WordArray 传递。如果它作为字符串传递,它被解释为 passphrase从中派生出一个 32 字节的 key 。
  • PHP 使用 0x00 值填充太短的键,直到达到指定长度。 CryptoJS 不会这样做,并且(由于 bug )通常在无效 key 的情况下为 AES 使用未定义的整数,因此预计不会有匹配的密文。
  • PHP 代码中使用了 PKCS7 填充(见评论)。这也必须应用于 CryptoJS 代码,但是它是 default (以及 CBC 模式)。

以下 PHP 代码:

function encrypt($stringData) {
    
  $ivMessage = "a";
  $apiSecret = "secret_key"; 

  $encrypted = false;
  $encrypt_method = 'AES-256-CBC';
  $iv = substr(hash('sha256', $ivMessage), 0, 16);
  $encrypted= openssl_encrypt($stringData, $encrypt_method, $apiSecret, 0, $iv);

  return $encrypted;
}

$stringData = '{"uid":19,"price":10000000,"duration":240,"credit_purpose":5,"new_tab":false,"cssFile":"kalkulatorok","css":[],"supported":false,"email":"test@test.hu","productType":"home_loan","method":"calculator","calculatorType":"calculator","unique":true}';
print(encrypt($stringData) . "\n");

返回结果:

d/H+FfTaT/3tIkaXtIix937p6Df/vlnxagNJGJ7ljj48phT7oA7QssTatL3WNZY0Igt0r5ObGyCt0AR0IccVTFVZdR+nzNe+RmKQEoD4dj0mRkZ7qi/y3bAICRpFkP3Nz42fuILKApRtmZqGLTNO6dwlCbUVvjg59fgh0wCzy15g51G6CYLsEHa89Dt193g4qcXRWFgI9gyY1Gq7FX0G6Ers0fySQjjNcfDJg0Hj5aSxbPU6EPn14eaWqkliNYSMqzKhe0Ev7Y54x2YlUCNQeLZhwWRM2W0N+jGU7W+P/bCtF4Udwv4cweUESXkHLGtlQ0K6O5etVJDtb7ZtdEI/sA==

下面的 CryptoJS 代码生成相同密文:

const IV_MESSAGE = "a";
const API_SECRET = "secret_key\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";

function encrypt(stringData){
    const iv = CryptoJS.SHA256(IV_MESSAGE).toString(CryptoJS.enc.Hex).substring(0, 16);
    const encrypted = CryptoJS.AES.encrypt(
        stringData, 
        CryptoJS.enc.Utf8.parse(API_SECRET), 
        {
            iv: CryptoJS.enc.Utf8.parse(iv)
        });

    return encrypted;
};

const stringData = {"uid":19,"price":10000000,"duration":240,"credit_purpose":5,"new_tab":false,"cssFile":"kalkulatorok","css":[],"supported":false,"email":"test@test.hu","productType":"home_loan","method":"calculator","calculatorType":"calculator","unique":true};
const ciphertextB64 = encrypt(JSON.stringify(stringData)).toString();

console.log(ciphertextB64.replace(/(.{64})/g,'$1\n'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

还应考虑以下因素:

  • 生成IV时避免将IV编码为十六进制字符串,直接使用二进制数据更可靠。否则,您还必须记住,根据平台的不同,通常可以应用不同大小写的十六进制数字。这在这里并不重要,因为在这两种情况下都使用小写。
  • 如果您真的应该应用像 secret_key 这样的密码短语作为 key ,您还应该使用合理的 key 派生函数(例如 PBKDF2 结合随机生成的盐),因为熵较低。 CryptoJS 中使用的默认 KDF,专有的 OpenSSL 函数 EVP_BytesToKey , 不应被应用,因为它不是标准并且也被认为是相对不安全的。
  • 出于安全原因,不得使用静态 IV。相反,应为每次加密应用随机生成的 IV。 IV 不是 secret 的,通常按照 IV 的顺序与密文连接,密文(见评论)。

关于javascript - 使用 CryptoJS (JAVASCRIPT) 和 OpenSSL (PHP) 实现相同的加密,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64379332/

相关文章:

javascript - 用PHP加密;用 CryptoJS 解密

php - 从哪里开始开发 WordPress/WooCommerce 主题?

java - 为什么远程服务器上的签名验证比设备上的签名验证更安全?

swift - Xcode Commoncrypto 生成 key 对(私钥和公钥)

javascript - 在按下或更改事件时,触发 Ajax 以在 jQuery 中发送数据

Javascript-随时间间隔改变背景颜色不透明度

php - 我如何查看已建立的套接字是否卡在期望输入的服务器上?

python 扭曲 : How to stop TLS?

javascript - 如何在 CodeMirror 中触发键盘事件?

javascript - 如何使用javascript从firebase中的嵌套数据库中检索所有子项