如何让dart:encrypt与crypto-js实现一致的加解密结果?
问题:Dart encrypt包与CryptoJS AES加解密一致性问题
我在Flutter项目中使用Dart的encrypt包实现AES加解密,由于需要在Flutter Web的Web Worker中复用逻辑,尝试改用CryptoJS的vanilla JS版本。目前无法实现两者在同一密钥下的加解密互通,需要解决双向兼容问题:Dart加密后JS能解密,JS加密后Dart能解密。
Dart端代码及运行结果
import 'package:encrypt/encrypt.dart'; void main() { final key = Key.fromUtf8("VishnuTestKeyIsHereLongValid32Ch"); final encrypter = Encrypter(AES(key)); final iv = IV.fromLength(16); // 生成16字节全0的IV var encrypted = encrypter.encrypt("Vishnu", iv: iv); print(encrypted.base64); // 输出:8beisXeeEE055QEPq+kumw== }
当前JS端代码(无法正确解密)
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
var base64Encrypted = '8beisXeeEE055QEPq+kumw==' var myKey = "VishnuTestKeyIsHereLongValid32Ch" var result = CryptoJS.AES.decrypt(base64Encrypted, myKey).toString(CryptoJS.enc.Utf8) console.log(result); // 无正确输出
问题根源及解决方案
两者无法互通的核心原因是密钥处理、IV配置、加密参数不匹配,具体修正如下:
- 统一密钥处理方式:Dart直接将UTF8字符串转为原始密钥;CryptoJS默认会对传入的字符串密钥执行PBKDF2推导,需在JS中直接将字符串转为UTF8格式的密钥,跳过推导步骤。
- 统一IV参数:Dart使用16字节全0IV,当前JS未指定IV导致自动生成随机IV,需显式配置相同的全0IV。
- 统一加密模式与填充方式:两者默认都是CBC模式+PKCS7填充,建议显式指定参数避免版本差异。
修正后的JS解密代码
var base64Encrypted = '8beisXeeEE055QEPq+kumw=='; var myKey = "VishnuTestKeyIsHereLongValid32Ch"; // 将密钥转为UTF8格式的WordArray var key = CryptoJS.enc.Utf8.parse(myKey); // 使用和Dart一致的16字节全0IV var iv = CryptoJS.enc.Utf8.parse('0000000000000000'); var decrypted = CryptoJS.AES.decrypt(base64Encrypted, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); console.log(decrypted.toString(CryptoJS.enc.Utf8)); // 输出:Vishnu
JS加密、Dart解密的兼容代码
JS加密代码
var plaintext = "Vishnu"; var myKey = "VishnuTestKeyIsHereLongValid32Ch"; var key = CryptoJS.enc.Utf8.parse(myKey); var iv = CryptoJS.enc.Utf8.parse('0000000000000000'); var encrypted = CryptoJS.AES.encrypt(plaintext, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); console.log(encrypted.toString()); // 输出与Dart加密一致的base64字符串
Dart解密JS加密内容的代码
import 'package:encrypt/encrypt.dart'; void main() { final key = Key.fromUtf8("VishnuTestKeyIsHereLongValid32Ch"); final encrypter = Encrypter(AES(key)); final iv = IV.fromLength(16); // 保持全0IV一致 // 传入JS加密生成的base64字符串 var decrypted = encrypter.decrypt(Encrypted.fromBase64("8beisXeeEE055QEPq+kumw=="), iv: iv); print(decrypted); // 输出:Vishnu }
内容的提问来源于stack exchange,提问作者Vishnu
相关产品推荐
相关产品推荐

