Flutter与Node.js双向加密方案问询(偏好AES256)
Flutter 与 Node.js 双向加密方案
一、RSA 双向加密实现
RSA 为非对称加密机制,前端用公钥加密数据,后端用私钥解密;后端用私钥签名数据,前端用公钥验签。该方案完全避开浏览器端依赖库,可彻底解决你遇到的window is undefined问题。
Flutter 端实现(依赖encrypt库)
- 在
pubspec.yaml添加依赖:
dependencies: encrypt: ^5.0.1
- 加密/验签代码示例:
import 'package:encrypt/encrypt.dart'; // 后端生成的PEM格式公钥 final publicKey = RSAKeyParser().parse('''-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...(完整公钥内容) -----END PUBLIC KEY-----''') as RSAPublicKey; // 公钥加密数据 String rsaEncrypt(String plainText) { final encrypter = Encrypter(RSA(publicKey: publicKey)); return encrypter.encrypt(plainText).base64; } // 公钥验签(验证后端私钥签名的内容) bool rsaVerify(String plainText, String signature) { final signer = Signer(RSASigner(RSASignDigest.SHA256, publicKey: publicKey)); return signer.verify(plainText, Signature(base64.decode(signature))); }
Node.js 端实现(原生crypto模块)
- 生成RSA密钥对(一次性操作,妥善保存私钥):
openssl genrsa -out private.key 2048 openssl rsa -in private.key -pubout -out public.key
- 解密/签名代码示例:
const crypto = require('crypto'); const fs = require('fs'); // 读取本地密钥文件 const privateKey = fs.readFileSync('./private.key', 'utf8'); const publicKey = fs.readFileSync('./public.key', 'utf8'); // 私钥解密前端加密数据 function rsaDecrypt(encryptedText) { const buffer = Buffer.from(encryptedText, 'base64'); return crypto.privateDecrypt( { key: privateKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256' }, buffer ).toString(); } // 私钥签名数据,供前端验签 function rsaSign(plainText) { const sign = crypto.createSign('SHA256'); sign.write(plainText); sign.end(); return sign.sign(privateKey, 'base64'); }
二、AES-256 双向加密实现
AES为对称加密,前后端共用32字节(256位)密钥,每次加密随机生成16字节IV,推荐使用CBC模式+PKCS7填充。
Flutter 端实现(依赖encrypt库)
import 'package:encrypt/encrypt.dart'; import 'dart:math'; // 32字节密钥(前后端必须完全一致,注意保密) final key = Key.fromUtf8('your-32-byte-secret-key-here-12345678'); // 生成随机16字节IV IV generateIV() => IV.fromBytes(List<int>.generate(16, (i) => Random.secure().nextInt(256))); // AES加密,返回加密数据和IV Map<String, String> aesEncrypt(String plainText) { final iv = generateIV(); final encrypter = Encrypter(AES(key, mode: AESMode.cbc)); final encrypted = encrypter.encrypt(plainText, iv: iv); return { 'data': encrypted.base64, 'iv': iv.base64 // IV需随加密数据一同传给后端 }; } // AES解密,接收加密数据和IV String aesDecrypt(String encryptedText, String ivBase64) { final iv = IV.fromBase64(ivBase64); final encrypter = Encrypter(AES(key, mode: AESMode.cbc)); return encrypter.decrypt(Encrypted.fromBase64(encryptedText), iv: iv); }
Node.js 端实现(原生crypto模块)
const crypto = require('crypto'); // 和Flutter端一致的32字节密钥 const key = Buffer.from('your-32-byte-secret-key-here-12345678', 'utf8'); // AES解密前端数据 function aesDecrypt(encryptedData) { const { data, iv } = encryptedData; const decipher = crypto.createDecipheriv('aes-256-cbc', key, Buffer.from(iv, 'base64')); let decrypted = decipher.update(data, 'base64', 'utf8'); decrypted += decipher.final('utf8'); return decrypted; } // AES加密返回给前端 function aesEncrypt(plainText) { const iv = crypto.randomBytes(16); // 生成随机IV const cipher = crypto.createCipheriv('aes-256-cbc', key, iv); let encrypted = cipher.update(plainText, 'utf8', 'base64'); encrypted += cipher.final('base64'); return { data: encrypted, iv: iv.toString('base64') }; }
关键注意事项
- RSA仅适合加密小数据(如AES密钥),AES适合加密大体积业务数据,实际项目可结合使用:用RSA加密AES密钥,再用AES加密核心数据。
- 密钥、私钥绝不能硬编码到代码中,建议通过环境变量或加密配置文件加载。
- IV必须每次加密随机生成,禁止固定使用同一IV,否则会大幅降低加密安全性。
内容的提问来源于stack exchange,提问作者exileValor
相关产品推荐
相关产品推荐

