简体   繁体   English

如何在nodejs应用程序中创建openssl加密和解密等效的php代码

[英]How to create openssl encryption and decryption equivalent of php code in nodejs application

I have an application running on php which have some values encrypted using openssl encrption by using the code below我有一个在 php 上运行的应用程序,其中一些值使用 openssl 加密通过使用下面的代码进行了加密

<?php
define('OSSLENCKEY','14E2E2D1582A36172AE401CB826003C1');
define('OSSLIVKEY', '747E314D23DBC624E971EE59A0BA6D28');

function encryptString($data) {
    $encrypt_method = "AES-256-CBC";
    $key = hash('sha256', OSSLENCKEY);    
    $iv = substr(hash('sha256', OSSLIVKEY), 0, 16); 
    $output = openssl_encrypt($data, $encrypt_method, $key, 0, $iv);
    $output = base64_encode($output);
    return $output;
}

function decryptString($data){
    $encrypt_method = "AES-256-CBC";
    $key = hash('sha256', OSSLENCKEY);    
    $iv = substr(hash('sha256', OSSLIVKEY), 0, 16);
    $output = openssl_decrypt(base64_decode($data), $encrypt_method, $key, 0, $iv);     
    return $output;
}

echo encryptString("Hello World");
echo "<br>";
echo decryptString("MTZHaEoxb0JYV0dzNnptbEI2UXlPUT09");
?>

I have another endpoint which runs on nodejs where I need to decrypt and encrypt values based on the above php encrypt/decrypt rule.我有另一个在 nodejs 上运行的端点,我需要根据上述 php 加密/解密规则来解密和加密值。 I have searched but could'nt find a solution for this.我已经搜索但找不到解决方案。

I tried with the library crypto But ends up with errors Reference我尝试使用库crypto但最终出现错误参考

My nodejs code which I have tried is given below我尝试过的nodejs代码如下

message         = 'MTZHaEoxb0JYV0dzNnptbEI2UXlPUT09';
const cypher    = Buffer.from(message, "base64");
const key       = crypto.createHash('sha256').update('14E2E2D1582A36172AE401CB826003C1');//.digest('hex');
// $iv          = substr(hash('sha256', '747E314D23DBC624E971EE59A0BA6D28'), 0, 16);  from php  returns '0ed9c2aa27a31693'  need nodejs equivalent
const iv        = '0ed9c2aa27a31693'; 
const decipher  = crypto.createDecipheriv("aes-256-cbc", key, iv);  
console.log( decipher.update(contents) + decipher.final());

Someone please help me to find a nodejs code for openssl encryption and decyption有人请帮我找到openssl加密和解密的nodejs代码

Thanks in advance提前致谢

There are the following problems in the code:代码中存在以下问题:

  • The key is returned hex encoded in the PHP code, so in the NodeJS code for AES-256 only the first 32 bytes must be considered for the key (PHP does this automatically).密钥以 PHP 代码中的十六进制编码返回,因此在 AES-256 的 NodeJS 代码中,只有前 32 个字节必须考虑密钥(PHP 自动执行此操作)。
  • The PHP code Base64 encodes the ciphertext implicitly, so because of the explicit Base64 encoding the ciphertext is Base64 encoded twice (which is unnecessary). PHP 代码 Base64 隐式编码密文,因此由于显式 Base64 编码密文被 Z1EB445FA6BD078346BF63 编码两次(这是不必要的)。 Therefore, a double Base64 encoding is necessary in the NodeJS code as well.因此,在 NodeJS 代码中也需要双 Base64 编码。

Also, note that using a static IV is insecure (but you are probably only doing this for testing purposes).另外,请注意使用 static IV 是不安全的(但您可能只是出于测试目的这样做)。

The following NodeJS code produces the same ciphertext as the PHP code:以下 NodeJS 代码生成与 PHP 代码相同的密文:

const crypto = require('crypto');

const plain =  'Hello World';
const hashKey = crypto.createHash('sha256');
hashKey.update('14E2E2D1582A36172AE401CB826003C1');
const key = hashKey.digest('hex').substring(0, 32);
  
const hashIv = crypto.createHash('sha256');
hashIv.update('747E314D23DBC624E971EE59A0BA6D28');
const iv = hashIv.digest('hex').substring(0, 16);
  
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
var encrypted = cipher.update(plain, 'utf-8', 'base64');
encrypted += cipher.final('base64');
encrypted = Buffer.from(encrypted, 'utf-8').toString('base64');
console.log(encrypted); // MTZHaEoxb0JYV0dzNnptbEI2UXlPUT09

encrypted = Buffer.from(encrypted, 'base64').toString('utf-8');
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
var decrypted = decipher.update(encrypted, 'base64', 'utf-8');
decrypted += decipher.final('utf-8');
console.log(decrypted); // Hello World

EDIT:编辑:

As mentioned in the comments, PHP's hash() method returns the hash as a hexadecimal string by default (unless the third parameter is explicitly set to true , which is not the case in the reference code).正如评论中提到的,PHP 的hash()方法默认返回 hash 作为十六进制字符串(除非第三个参数显式设置为true ,参考代码中不是这种情况)。 This doubles the length, because in this encoding each byte of the hash is represented by two hex digits (hexits), ie 2 bytes.这使长度加倍,因为在这种编码中 hash 的每个字节由两个十六进制数字(hexits)表示,即 2 个字节。
Therefore it is necessary to shorten the key in the NodeJS code (see the first point of my original answer).因此有必要缩短 NodeJS 代码中的密钥(参见我原始答案的第一点)。 This shortening is not necessary in the PHP code, since PHP does this implicitly (which is actually a design flaw, since this way the user does not notice a possible issue with the key). PHP 代码中不需要这种缩短,因为 PHP隐含地这样做(这实际上是一个设计缺陷,因为这样用户不会注意到密钥可能存在的问题)。

The use of the hex string has two disadvantages:使用十六进制字符串有两个缺点:

  • With a hex encoded string, each byte consists of 16 possible values (0-15), as opposed to 256 possible values of a byte (0-255).对于十六进制编码的字符串,每个字节由 16 个可能的值 (0-15) 组成,而不是一个字节的 256 个可能的值 (0-255)。 This reduces the security from 256 bit to 128 bit (which is arithmetically equivalent to AES-128), see here .这将安全性从 256 位降低到 128 位(在算术上等同于 AES-128),请参见此处
  • Depending on the platform, the hexits af can be represented as lowercase or uppercase letters, which can result in different keys and IVs (without explicit agreement on one of the two cases).根据平台的不同,十六进制 af 可以表示为小写或大写字母,这可能导致不同的键和 IV(在两种情况之一上没有明确的约定)。

For these reasons it is more secure and robust to use the raw binary data of the hash instead of the hex encoded strings.由于这些原因,使用 hash 的原始二进制数据而不是十六进制编码的字符串更加安全和稳健。 If you want to do this, then the following changes are necessary.如果要执行此操作,则需要进行以下更改。

In the PHP code:在 PHP 代码中:

$key = hash('sha256', OSSLENCKEY, true);    
$iv = substr(hash('sha256', OSSLIVKEY, true), 0, 16); 

in the NodeJS code:在 NodeJS 代码中:

const key = hashKey.digest();
const iv = hashIv.digest().slice(0, 16)

Note, however, that this version is not compatible with the old one, ie encryptions before this change cannot be decrypted after the change.但是请注意,此版本与旧版本不兼容,即更改之前的加密无法在更改之后解密。 So the old data would have to be migrated.因此,必须迁移旧数据。

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

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