NodeJS无法解密C++ AES-256-CBC加密字符串问题求助
AES256-CBC跨语言解密失败问题解决
问题背景
我用C的OpenSSL AES库加密字符串,转Base64后发送给NodeJS服务解密,但NodeJS始终解密失败。采用AES256 CBC算法,C端已手动实现PKCS#7填充逻辑。
核心问题
C++与NodeJS对密钥(key)和初始化向量(IV)的解析逻辑完全不一致:
- C++端:直接把字符串当作ASCII字节数组使用。比如
aes_key是64个字符的字符串,AES256取前32个字符的ASCII值作为密钥;aes_iv是32个字符的字符串,取前16个字符的ASCII值作为IV。 - NodeJS端:用
Buffer.from(..., 'hex')解析,把字符串当作十六进制编码处理——64个字符会被解析成32字节密钥,32个字符解析成16字节IV,和C++端的字节内容完全不匹配。
修复方案
统一两端的key/IV解析逻辑,以下两种方案二选一:
方案一:修改NodeJS端,匹配C++的ASCII解析逻辑
将NodeJS的key和IV改为直接取字符串的ASCII字节,并截取对应长度:
const express = require('express'); const bodyParser = require('body-parser'); const crypto = require('crypto'); const app = express(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); // 修改key和IV的解析方式,与C++对齐 const aes_key = Buffer.from("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", 'utf8').slice(0, 32); const aes_iv = Buffer.from("0123456789abcdef0123456789abcdef", 'utf8').slice(0, 16); function DecryptAES(cipherText) { const decipher = crypto.createDecipheriv('aes-256-cbc', aes_key, aes_iv); let decrypted = decipher.update(cipherText, 'base64', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } app.post('/decrypt', (req, res) => { const { encryptedText } = req.body; if (!encryptedText) { return res.status(400).json({ error: 'Missing encryptedText in request body' }); } try { const decryptedText = DecryptAES(encryptedText); res.send(decryptedText); console.log(decryptedText); } catch (error) { console.error('Decryption failed:', error); res.status(500).send('Decryption failed'); } }); const port = 3000; app.listen(port, () => { console.log(`Server is running on http://localhost:${port}`); });
方案二:修改C++端,匹配NodeJS的十六进制解析逻辑
在C++中新增十六进制转字节数组的函数,将key和IV字符串按十六进制解析后再使用:
#include <iostream> #include <string> #include <openssl/aes.h> #include <vector> #include <sstream> #include <iomanip> #include "base64.h" using namespace std; // 新增:十六进制字符串转字节数组 vector<unsigned char> hex_to_bytes(const string& hex_str) { vector<unsigned char> bytes; for (size_t i = 0; i < hex_str.length(); i += 2) { string byte_sub = hex_str.substr(i, 2); unsigned char byte = static_cast<unsigned char>(strtol(byte_sub.c_str(), nullptr, 16)); bytes.push_back(byte); } return bytes; } // AES加密密钥和IV的十六进制字符串 const string aes_key_hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; const string aes_iv_hex = "0123456789abcdef0123456789abcdef"; string EncryptAES(const string& plainText) { AES_KEY enc_key; vector<unsigned char> aes_key = hex_to_bytes(aes_key_hex); AES_set_encrypt_key(aes_key.data(), 256, &enc_key); // PKCS#7填充逻辑不变 int paddingLength = AES_BLOCK_SIZE - (plainText.length() % AES_BLOCK_SIZE); if (paddingLength == 0) { paddingLength = AES_BLOCK_SIZE; } string paddedText = plainText; for (int i = 0; i < paddingLength; ++i) { paddedText.push_back(static_cast<char>(paddingLength)); } // 加密逻辑,使用解析后的IV vector<unsigned char> aes_iv = hex_to_bytes(aes_iv_hex); string cipherText; cipherText.resize(paddedText.length()); AES_cbc_encrypt(reinterpret_cast<const unsigned char*>(paddedText.c_str()), reinterpret_cast<unsigned char*>(&cipherText[0]), paddedText.length(), &enc_key, aes_iv.data(), AES_ENCRYPT); return cipherText; } int main() { string plainText = "Hello, this is a secret message."; string encryptedText = EncryptAES(plainText); auto encodedText = base64_encode(encryptedText); cout << "Encoded text: " << encodedText << endl; return 0; }
验证说明
修改后NodeJS端无需修改自动填充逻辑(默认开启PKCS#7填充匹配C++端),用你提供的测试Base64字符串即可正常解密出明文。
内容的提问来源于stack exchange,提问作者user12679450
相关产品推荐
相关产品推荐

