php - 将加密/解密函数从 PHP 转换为 NodeJS

标签 php node.js encryption

我正在考虑将一个项目从 PHP 移植到 NodeJS,其中包含一个用于加密和解密字符串的加密/解密类,我正在尝试将其转换为 NodeJS。

下面是现有的 PHP 函数

public function encrypt($data): string
{
    return base64_encode(openssl_encrypt($data, 'AES-256-CBC', $this->cipher_key,
        OPENSSL_RAW_DATA, $this->iv));
}

public function decrypt($encryptedString)
{
    try
    {
        return $this->strippadding(openssl_decrypt(base64_decode($encryptedString), 'AES-256-CBC',
        $this->cipher_key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv));
    }
    catch (\Exception $e)
    {
        Logger::log("Failed to decrypt string. Error: " . $e->getMessage());
        return $encryptedString;
    }
}

private function strippadding($string)
{
    error_reporting(0);
    $slast = ord(substr($string, -1));
    $slastc = chr($slast);
    //$pcheck = substr($string, -$slast);
    if(preg_match('/'.$slastc.'{'.$slast.'}/', $string)){
        return substr($string, 0, strlen($string)-$slast);
    } else {
        return null;
    }
}

下面是我移植到 NodeJS 的代码

const encrypt = (data, key, iv) => {
    const cipher = crypto.createCipheriv('AES-256-CBC', key, iv);
    let encrypted = cipher.update(data, 'utf8', 'base64');
    encrypted += cipher.final('base64');
    return encrypted;
}

const decrypt = (encryptedString, key, iv) => {
    try {
        const decipher = crypto.createDecipheriv('AES-256-CBC', key, iv);
        decipher.setAutoPadding(false);
        let decrypted = decipher.update(encryptedString, 'base64', 'utf-8');
        decrypted += decipher.final('utf-8');
        return strippadding(decrypted);
        return decrypted
    } catch (e) {
        console.log(`Failed to decrypt string. Error: ${e.message}`);
        return encryptedString;
    }
}

const strippadding = (string) => {
    const slast = string.charCodeAt(string.length - 1);
    const slastc = String.fromCharCode(slast);
    const regex = new RegExp(`${slastc}{${slast}}`);
    if (regex.test(string)) {
        return string.substring(0, string.length - slast);
    } else {
        return null;
    }
}

当我尝试获取现有的加密字符串并使用相同的 key 和 iv 对其进行解密时,我得到一个 NULL 返回,因为 strippadding 函数中的正则表达式似乎不起作用,但我不明白为什么。如果我不使用 strippadding 而只是打印解密的变量,我只会得到随机符号。

如果我尝试加密一个字符串,我会得到与我期望的完全不同的字符串,所以我有一些不太正确的东西,但不确定是什么。

最佳答案

因为根据您的评论,实现应该只解密使用 encrypt() 方法生成的密文,并且 encrypt() 方法应用默认的 PKCS# 7 填充,默认的 PKCS#7 填充也可以用于解密,即不再需要自定义取消填充 strippadding()。一个可能的 NodeJS 实现是:

var crypto = require('crypto');

const encrypt = (data, key, iv) => {
    const cipher = crypto.createCipheriv('AES-256-CBC', key, iv);
    let encrypted = cipher.update(data, 'utf8', 'base64');
    encrypted += cipher.final('base64');
    return encrypted;
}

const decrypt = (encryptedString, key, iv) => {
    try {
        const decipher = crypto.createDecipheriv('AES-256-CBC', key, iv);
        let decrypted = decipher.update(encryptedString, 'base64', 'utf-8');
        decrypted += decipher.final('utf-8');
        return decrypted
    } catch (e) {
        console.log(`Failed to decrypt string. Error: ${e.message}`);
        return encryptedString;
    }
}

iv = '0123456789012345';
key = '01234567890123456789012345678901';
plaintext = 'The quick brown fox jumps over the lazy dog';
ciphertext = encrypt(plaintext, key, iv);
console.log(ciphertext); // 4G9jpxHot6qflEAQfUaAoReZQ4DqMdKimblTAtQ5uXAsjmWpkjbskgcEkVzxqYpE
decrypted = decrypt(ciphertext, key, iv);
console.log(decrypted); // The quick brown fox jumps over the lazy dog

测试:以下 PHP 代码使用发布的方法 enrypt() 和定制的 decrypt():

class Test {
    private $iv = '0123456789012345';
    private $cipher_key = '01234567890123456789012345678901';
    public function encrypt($data)
    {
        return base64_encode(openssl_encrypt($data, 'AES-256-CBC', $this->cipher_key, OPENSSL_RAW_DATA, $this->iv));
    }
    public function decrypt($data)
    {
        try
        {
            return openssl_decrypt(base64_decode($data), 'AES-256-CBC', $this->cipher_key, OPENSSL_RAW_DATA, $this->iv);
        }
        catch (\Exception $e)
        {
            Logger::log("Failed to decrypt string. Error: " . $e->getMessage());
            return $encryptedString;
        }
    }
}

$test = new Test();
$plaintext = 'The quick brown fox jumps over the lazy dog';
$ciphertext = $test->encrypt($plaintext);
print($ciphertext . PHP_EOL); // 4G9jpxHot6qflEAQfUaAoReZQ4DqMdKimblTAtQ5uXAsjmWpkjbskgcEkVzxqYpE
$decrypted = $test->decrypt($ciphertext);
print($decrypted . PHP_EOL); // The quick brown fox jumps over the lazy dog

对于相同的 key 和明文,密文与 NodeJS 代码相同,解密后的文本类似。

关于php - 将加密/解密函数从 PHP 转换为 NodeJS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74828615/

相关文章:

c++ - 解密前检查密码

php - 无法在 php 中使用 preg_match 通过特殊符号分割字符串

带有限制的php mysql select语句

node.js - 为 npm 注册表 URL 设置用户名和密码

node.js - 出现错误 : Can't set headers after they are sent

node.js - 我如何在 sequelizejs 中使用这个完整的查询

java - 使用 RSA 加密字符串并将 Java 中的 key 封装到文件中

java - 使用加密货币进行加密。加密失败,解密正常

php - MySQL查询仅显示按用户分组的最后一个项目

php - DBXML 错误 centos 5.5(64bit) 和 php 5.2