NodeJS服务器RSA加密,Flutter客户端解密方案求助
NodeJS RSA加密 + Flutter 解密可行方案
核心问题原因
加密解密失败通常是密钥格式不兼容、填充/哈希算法不匹配导致的,以下是统一配置后的可运行方案。
第一步:标准化NodeJS端加密代码
确保node-rsa的加密参数与Flutter端兼容,显式指定填充方式、哈希算法和密钥格式:
const NodeRSA = require('node-rsa'); // 生成2048位密钥对,指定PKCS1_OAEP填充、SHA-256哈希(Flutter端易支持) const key = new NodeRSA({b: 2048}, { encryptionScheme: 'pkcs1_oaep', hash: 'sha256' }); // 导出标准PKCS8格式的公钥/私钥 const publicKeyPem = key.exportKey('pkcs8-public-pem'); const privateKeyPem = key.exportKey('pkcs8-private-pem'); console.log('公钥(用于加密):\n', publicKeyPem); console.log('私钥(用于Flutter解密):\n', privateKeyPem); // 加密文本,输出base64格式 const text = 'Hello RSA!'; const encrypted = key.encrypt(text, 'base64'); console.log('加密结果:', encrypted);
第二步:Flutter端解密实现
使用pointycastle(最可靠的加密底层库)实现对应解密逻辑:
1. 添加依赖
在pubspec.yaml中加入:
dependencies: pointycastle: ^3.7.3 convert: ^3.1.1
2. 解密代码实现
import 'dart:convert'; import 'package:pointycastle/asymmetric/api.dart'; import 'package:pointycastle/asymmetric/oaep.dart'; import 'package:pointycastle/asymmetric/rsa.dart'; import 'package:pointycastle/digests/sha256.dart'; import 'package:pointycastle/random/fortuna_random.dart'; import 'package:pointycastle/asymmetric/asn1.dart'; // 解析PKCS8格式PEM私钥为RSAPrivateKey RSAPrivateKey parsePrivateKeyFromPem(String pem) { // 去除PEM头、尾和换行 final cleanPem = pem.split('\n') .where((line) => !line.startsWith('-----BEGIN') && !line.startsWith('-----END') && line.isNotEmpty) .join(''); final keyBytes = base64Decode(cleanPem); final asn1Parser = ASN1Parser(keyBytes); final seq = asn1Parser.nextObject() as ASN1Sequence; return RSAPrivateKey( (seq.elements[1] as ASN1Integer).valueAsBigInteger, (seq.elements[2] as ASN1Integer).valueAsBigInteger, (seq.elements[3] as ASN1Integer).valueAsBigInteger, (seq.elements[4] as ASN1Integer).valueAsBigInteger, (seq.elements[5] as ASN1Integer).valueAsBigInteger, (seq.elements[6] as ASN1Integer).valueAsBigInteger, (seq.elements[7] as ASN1Integer).valueAsBigInteger, (seq.elements[8] as ASN1Integer).valueAsBigInteger, ); } // RSA解密函数 String rsaDecrypt(String encryptedBase64, String privateKeyPem) { final privateKey = parsePrivateKeyFromPem(privateKeyPem); // 对应NodeJS端的PKCS1_OAEP + SHA-256配置 final cipher = OAEPEncoding(RSAEngine()) ..init( false, // false代表解密模式 ParametersWithRandom( PrivateKeyParameter<RSAPrivateKey>(privateKey), FortunaRandom(), ), OAEPParameters(SHA256Digest(), SHA256Digest(), null), ); final encryptedBytes = base64Decode(encryptedBase64); final decryptedBytes = cipher.process(encryptedBytes); return utf8.decode(decryptedBytes); } // 使用示例 void main() { const encryptedStr = "替换为NodeJS输出的加密字符串"; const privateKey = "替换为NodeJS导出的PKCS8私钥"; final result = rsaDecrypt(encryptedStr, privateKey); print("解密结果:$result"); // 输出 Hello RSA! }
关键兼容注意事项
- 填充/哈希必须完全匹配:如果NodeJS端改用
pkcs1填充,Flutter端需替换为PKCS1Encoding(RSAEngine()),哈希算法也要对应一致 - 密钥格式统一:必须用PKCS8格式,避免node-rsa默认的其他格式导致Flutter解析失败
- 密钥长度一致:两端都使用2048位(或4096位)密钥,不要混用不同长度
内容的提问来源于stack exchange,提问作者Divyanshu Sah
相关产品推荐
相关产品推荐

