You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将PHP的openssl_seal函数移植到Node.js 18?

Node.js 适配 PHP openssl_seal() 功能方案

问题背景

需要将PHP中可正常运行的openssl_seal()加密逻辑移植到Node.js,PHP后端通过openssl_open()解密,但自行编写的Node.js代码输出格式正确,却始终无法被后端解密成功。

PHP 参考代码

加密逻辑

$ivLength = openssl_cipher_iv_length('AES-256-CBC') ?: 16;

$iv = openssl_random_pseudo_bytes($ivLength);

openssl_seal(
    data: json_encode($data),
    sealed_data: $sealed,
    encrypted_keys: $encryptedKeys,
    public_key: [openssl_get_publickey("my-public-key")],
    cipher_algo: 'AES-256-CBC',
    iv: $iv
);

return [
    'context' => base64_encode($sealed),
    'envelope' => base64_encode($encryptedKeys[0]),
    'vector' => base64_encode($iv),
];

解密逻辑

$privateKey = openssl_pkey_get_private("my-private-key");

openssl_open(
    data: base64_decode($data['context']),
    output: $context,
    encrypted_key: base64_decode($data['envelope']),
    private_key: $privateKey,
    cipher_algo: 'AES-256-CBC',
    iv: base64_decode($data['vector'])
);

原Node.js代码问题

const algorithm = "aes-256-cbc";
const publicKey = loadPublicKey();

const key = Buffer.from(crypto.randomBytes(32), "binary");
const ivLength = crypto.randomBytes(16).length;
const iv = crypto.randomBytes(ivLength);

const cipher = crypto.createCipheriv(algorithm, key, iv);

let sealedData = cipher.update(data, "utf8", "binary");
sealedData += cipher.final("binary");

const encryptedKeys = crypto.publicEncrypt(publicKey, iv);

return {
  context: Buffer.from(sealedData).toString("base64"),
  envelope: encryptedKeys.toString("base64"),
  vector: iv.toString("base64"),
};

存在两个核心错误:

  • 加密对象错误:openssl_seal()的核心逻辑是用公钥加密随机生成的AES密钥,而非IV。原代码错误地加密了IV,导致后端无法解密出正确的AES密钥。
  • 冗余的密钥处理:Buffer.from(crypto.randomBytes(32), "binary")完全多余,crypto.randomBytes(32)直接返回符合要求的Buffer类型密钥。

修正后的Node.js代码

const crypto = require('crypto');
const algorithm = "aes-256-cbc";

function sealData(data, publicKey) {
    // 生成AES-256所需的32字节随机密钥
    const aesKey = crypto.randomBytes(32);
    // 生成AES-CBC标准的16字节IV
    const iv = crypto.randomBytes(16);

    // 加密原始数据(对齐PHP的json_encode+AES加密流程)
    const cipher = crypto.createCipheriv(algorithm, aesKey, iv);
    let sealedData = cipher.update(JSON.stringify(data), 'utf8');
    sealedData = Buffer.concat([sealedData, cipher.final()]);

    // 用公钥加密AES密钥,显式指定PKCS1填充(和PHP默认逻辑一致)
    const encryptedAesKey = crypto.publicEncrypt({
        key: publicKey,
        padding: crypto.constants.RSA_PKCS1_PADDING
    }, aesKey);

    return {
        context: sealedData.toString('base64'),
        envelope: encryptedAesKey.toString('base64'),
        vector: iv.toString('base64')
    };
}

关键适配点

  1. 严格对齐openssl_seal()的流程:生成随机AES密钥→用AES密钥+IV加密数据→用公钥加密AES密钥
  2. 显式指定RSA填充模式,避免环境差异导致的兼容问题
  3. 使用Buffer拼接加密结果,避免二进制编码转换错误

内容的提问来源于stack exchange,提问作者Levente Otta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 22:05:07