You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 00:35:20