如何在Flutter Dart中解密NestJS AES-256-CTR加密字符串?
问题分析与解决
核心错误点
你的Flutter解密代码存在三个关键问题,导致了"Input data length must be a multiple of cipher's block size"错误:
- 密钥未经过scrypt推导:JS代码里的密钥是通过
scrypt(secretKey, 'salt', 32)生成的32字节密钥,而你直接把原始的secretKey用fromUtf8当作密钥,完全跳过了scrypt推导步骤。 - IV的编码方式错误:JS里的IV是将字符串
q2Q@w3W#转成hex得到7132514077335723,所以Flutter里应该用IV.fromHex()解析这个hex字符串,而不是fromUtf8(后者会把hex字符串当成普通UTF-8字符处理,得到错误的字节序列)。 - 密文解码方式错误:JS输出的密文是hex格式,但你用了
decrypt64(用于Base64编码的密文),应该先把hex密文转成字节数组,再用decrypt方法。
修正后的代码
首先添加依赖到pubspec.yaml:
dependencies: encrypt: ^5.0.3 crypto: ^3.0.3 # 用于scrypt密钥推导
然后修改解密函数:
import 'package:encrypt/encrypt.dart'; import 'package:crypto/crypto.dart'; import 'dart:convert'; void decrypt() { try { // 1. 用scrypt推导32字节密钥,和JS逻辑完全对齐 final secretKey = 'H4WtkvK4qyehIe2kjQfH7we1xIHFK67e'; final salt = utf8.encode('salt'); // scrypt参数和Node.js默认值保持一致:N=1<<14, r=8, p=1 final keyBytes = scrypt(utf8.encode(secretKey), salt, 32, N: 1 << 14, r: 8, p: 1); final ivKey = Key(keyBytes); // 2. 从hex字符串解析IV,确保字节序列和JS一致 final ivHex = "7132514077335723"; final iv = IV.fromHex(ivHex); // 3. 将hex格式的密文转成字节数组,再执行解密 final encryptedHex = "222ef6e4c66c3dfdea9cf1f4828f436e"; final encryptedBytes = hex.decode(encryptedHex); final encrypter = Encrypter(AES(ivKey, mode: AESMode.ctr)); final String decrypted = encrypter.decrypt(Encrypted(encryptedBytes), iv: iv); setState(() { text = decrypted; }); } catch (e) { debugPrint(e.toString()); } }
关键注意事项
- scrypt的参数必须和Node端保持一致,否则生成的密钥会不同,导致解密失败。
- CTR模式本身不需要填充,但错误的密钥/IV/密文格式会触发块大小不匹配的错误,本质是因为输入的字节序列不符合解密要求。
内容的提问来源于stack exchange,提问作者Dowlpack
相关产品推荐
相关产品推荐

