我正在考虑将一个项目从PHP移植到NodeJS,其中包含一个用于加密和解密字符串的加密/解密类,我正在try 将其转换为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;
    }
}

当我try 获取一个已有的加密字符串并使用相同的密钥和IV对其进行解密时,我得到了一个空的返回值,因为带添加函数中的正则表达式似乎不起作用,但我看不出原因.如果我不使用条带化,而只是打印解密的变量,我只会得到随机符号.

如果我try 加密一个字符串,那么我得到的字符串与我期望的完全不同,所以我得到了一些不太正确的东西,但不确定是什么.

推荐答案

因为根据您的 comments ,实现应该只解密用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代码使用POST方法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

对于相同的密钥和明文,密文与NodeJS代码相同,类似于解密的文本.

Php相关问答推荐

Symfony Monolog:使用多个格式化程序

根据在WooCommerce购物车和 checkout 中 Select 的送货方式显示快捷代码内容

从含有特殊字符的ANSI文本文件中读取数据是在移值,为什么?

从WC会话变量更改WooCommerce checkout 托运方法成本

创建一个新的可变产品及其属性以用于WooCommerce中的变体

获取并判断WooCommerce用户订阅结束日期

如何从Laravel中的Spatie\Dns\Records\A对象中提取IP地址

Laravel服务Provider 没有向服务类注入价值

从字符串转换日期和/或时间时,Laravel转换失败

Laravel Http::get not working on controller

Laravel处理belongToMany和额外字段

未定义的类型';PDF';在Laravel 8

PHP 支持 APNG 文件吗?

单个产品页面 WooCommerce 订阅价格字符串的更改

simplexml_load_file 和 simplexml_load_string 返回具有不同编码的相同数据

从插件更改主题功能,function_exists 不起作用

加载 Xdebug PHP 7.4.0 失败

如何通过帖子自定义元数据进行查询

根据数组中的文本文件编号显示星级

PHP - 如何获取发送到脚本的查询参数