我正在考虑将一个项目从 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/