Flutter中encrypt包AES128加密结果长度超出16字节问题
Flutter AES-128加密问题:十六进制明文转字符串后加密结果长度异常
我正在开发Flutter项目,需要对十六进制格式的明文和密钥进行AES-128加密。使用encrypt包时发现,该包仅接受字符串类型的明文,多数在线AES工具也默认明文为字符串。尝试将十六进制转为字符串后加密,结果长度始终超过16字节,且仅在含特殊字符的特定字符串中出现此问题,其他字符串的密文长度符合预期。
参数信息
- 密钥(KEY):
B0A42687AA50A67A6DCEB68EA59A1332(16字节) - 明文(Plaintext):
A0A1A2A3A4A5A6A7B1B2B3B4B5B6B7B0(16字节) - 预期密文(Expected Ciphertext):
D704CE5AAE286511A691AF8EF7D31FE1(16字节)
已尝试的方案及结果
方案1:直接将十六进制字符串作为明文传入
void main() { final plainText = 'A0A1A2A3A4A5A6A7B1B2B3B4B5B6B7B0'; // 原始十六进制当作字符串处理 final key = Key.fromBase16('0A42687AA50A67A6DCEB68EA59A1332'); // 密钥缺失开头的B0 final iv = IV.fromLength(16); final encrypter = Encrypter(AES(key, mode: AESMode.ebc, padding: null)); final encrypted = encrypter.encrypt(plainText, iv: iv); final decrypted = encrypter.decrypt(encrypted, iv: iv); print(encrypted.base16); // 输出:477eobf5f216745a7b1daf703218861b2c26ba77843429adc8928a164cccc435 }
问题:实际加密的是十六进制字符串的ASCII字符序列,而非十六进制对应的原始字节,导致密文长度远超16字节。
方案2:将十六进制转为对应字符串后传入
void main() { final plainText = ' ¡¢£¤¥¦§±²³´µ¶·°'; // 十六进制转成对应的字符串 final key = Key.fromBase16('0A42687AA50A67A6DCEB68EA59A1332'); // 密钥缺失开头的B0 final iv = IV.fromLength(16); final encrypter = Encrypter(AES(key, mode: AESMode.ebc, padding: null)); final encrypted = encrypter.encrypt(plainText, iv: iv); final decrypted = encrypter.decrypt(encrypted, iv: iv); print(encrypted.base16); // 输出:268ceb0611e696ab9eeb4b87d51c60eedfd54a8755c5df5b3f657ee2b93936 }
问题:十六进制转字符串时默认使用UTF-8编码,部分字符对应多字节编码,导致明文字节数超过16,加密后密文长度随之增加。
正确解决方案
核心是直接加密十六进制对应的原始字节数组,而非字符串。encrypt包提供了encryptBytes方法可直接处理字节数组,避免编码转换带来的问题。
正确代码
import 'package:encrypt/encrypt.dart'; import 'dart:convert'; void main() { // 将十六进制明文转为原始字节数组 final plainHex = 'A0A1A2A3A4A5A6A7B1B2B3B4B5B6B7B0'; final plainBytes = hex.decode(plainHex) as Uint8List; // 修正密钥并转为Key对象 final keyHex = 'B0A42687AA50A67A6DCEB68EA59A1332'; final key = Key.fromBase16(keyHex); // ECB模式无需IV,但包要求传入,生成16字节长度的IV即可 final iv = IV.fromLength(16); // 初始化加密器:ECB模式,禁用padding(明文正好16字节) final encrypter = Encrypter(AES(key, mode: AESMode.ecb, padding: null)); // 直接加密字节数组 final encrypted = encrypter.encryptBytes(plainBytes, iv: iv); // 输出与预期一致的十六进制密文 print(encrypted.base16.toUpperCase()); // 输出:D704CE5AAE286511A691AF8EF7D31FE1 }
关键说明
- 使用
dart:convert的hex.decode将十六进制字符串转为原始字节数组,确保明文正好是16字节 - 调用
encryptBytes方法直接加密字节,避免字符串编码导致的字节数变化 - 修正密钥拼写错误(原代码缺失开头的
B0) - ECB模式下IV不生效,但包要求必须传入,因此生成一个16字节的IV即可
内容的提问来源于stack exchange,提问作者Adnan Arshad
相关产品推荐
相关产品推荐

