繁体   English   中英

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

[英]Achieve same encryption using CryptoJS (JAVASCRIPT) and OpenSSL (PHP)

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

与 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;
}

爪哇脚本:

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 代码密文所必需的:

  • 密钥必须作为WordArray传递。 如果它作为字符串传递,它会被解释为一个密码短语,从中派生出一个 32 字节的密钥。
  • PHP 用 0x00 值填充太短的键,直到指定的长度。 CryptoJS 不这样做,并且(由于错误)通常在密钥无效的情况下为 AES 使用未定义的整数,因此预计不会出现匹配的密文。
  • PHP 代码中使用了 PKCS7 填充(请参阅注释)。 这也必须应用于 CryptoJS 代码,但这是默认的(以及 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这样的密码短语作为密钥,你还应该使用合理的密钥派生函数(例如 PBKDF2 与随机生成的盐相结合),因为低熵。 CryptoJS 中使用的默认 KDF,专有 OpenSSL 函数EVP_BytesToKey不应应用,因为它不是标准并且也被认为相对不安全。
  • 出于安全原因,不得使用静态 IV。 相反,应该为每个加密应用随机生成的 IV。 IV 不是秘密的,通常按照 IV,密文的顺序与密文连接(见评论)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM