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

Flutter中使用encrypt包实现Rijndael/AES加密未得到预期结果

Flutter平台Rijndael加密实现方案与问题排查

Flutter生态有成熟的Rijndael加密实现可直接使用。注意AES是Rijndael算法在分组长度固定为128位时的标准化子集:如果对接场景使用标准AES参数(128/192/256位密钥、128位分组、CBC/ECB等常用模式+PKCS7填充),encrypt库即可满足需求;如果对接老系统使用非标准Rijndael参数(如192/256位分组长度),可直接基于底层密码库pointycastle的Rijndael核心实现自定义逻辑。

现有代码加密结果不匹配的核心原因

  • 代码语法错误:你当前代码中padding: "PKCS7"写法有误,encrypt库的AES构造函数要求padding参数传入Padding类型实例,而非字符串,该写法会导致填充逻辑不生效,默认填充行为与预期不符。正确写法应为padding: PKCS7Padding()。
  • 密钥/IV编码错误:你使用Key.fromUtf8()、IV.fromUtf8()将密钥、IV字符串按UTF8编码转字节,这是最常见的不匹配原因。绝大多数业务加密场景下,对接方提供的Key、IV为十六进制字符串或Base64字符串,并非明文UTF8字符串,用UTF8解码得到的字节数组与预期完全不符,会直接导致加密结果错误。需根据Key/IV的实际格式选择对应转换方法:
    • 十六进制格式Key/IV:使用Key.fromBase16()、IV.fromBase16()转换
    • Base64格式Key/IV:使用Key.fromBase64()、IV.fromBase64()转换
    • 仅当Key/IV本身为UTF8明文字符串、且转字节后长度严格为16/24/32位时,才使用fromUtf8()转换
  • 明文格式不匹配:CBC模式下只要明文字节存在1位差异,从差异位置开始的后续所有密文块都会完全不同。你直接传入JSON对象序列化结果加密,需确认:
    • JSON序列化规则与对接方完全一致:包括键值对顺序、数字类型序列化格式(如整数0是否会被序列化为0.0)、null值处理逻辑、是否存在多余空格/换行/转义字符
    • 加密前是否需要对明文做额外处理(如Base64编码、拼接固定前后缀),部分业务接口会有自定义明文规则
  • 算法参数不匹配:encrypt库封装的AES实现仅支持128位分组的标准AES,如果对接方使用的是192/256位分组的原生Rijndael算法,该库无法支持,需切换到底层pointycastle实现。

正确实现代码示例

标准AES(Rijndael-128)CBC+PKCS7实现

首先在pubspec.yaml添加依赖:

dependencies:
  encrypt: ^5.0.3

加密方法实现:

import 'dart:convert';
import 'package:encrypt/encrypt.dart';

String encrypterAESdata({
  required String data,
  required String aesKey,
  required String aesIv,
  // 传入key/iv的格式:utf8/base16/base64
  String keyFormat = 'utf8',
  String ivFormat = 'utf8',
}){
  // 根据格式转换Key
  late final Key key;
  switch(keyFormat){
    case 'base16':
      key = Key.fromBase16(aesKey);
      break;
    case 'base64':
      key = Key.fromBase64(aesKey);
      break;
    default:
      key = Key.fromUtf8(aesKey);
  }
  // 根据格式转换IV
  late final IV iv;
  switch(ivFormat){
    case 'base16':
      iv = IV.fromBase16(aesIv);
      break;
    case 'base64':
      iv = IV.fromBase64(aesIv);
      break;
    default:
      iv = IV.fromUtf8(aesIv);
  }
  // 正确传入PKCS7Padding实例
  final encrypter = Encrypter(AES(key, mode: AESMode.cbc, padding: PKCS7Padding()));
  final encrypted = encrypter.encrypt(data, iv: iv);
  return encrypted.base64;
}

使用时需注意,序列化JSON要固定规则,避免格式差异:

// 固定JSON序列化规则,避免键顺序、类型转换导致的明文差异
final plainText = jsonEncode(yourJsonObject, toEncodable: (dynamic obj) => obj?.toString());
// 调用加密方法,根据实际key/iv格式传入对应format参数
final encryptedResult = encrypterAESdata(
  data: plainText,
  aesKey: yourAesKey,
  aesIv: yourAesIv,
  keyFormat: 'base64', // 替换为实际key格式
  ivFormat: 'base64', // 替换为实际iv格式
);

非标准分组长度Rijndael实现

如果对接场景使用192/256位分组的原生Rijndael,使用pointycastle实现,添加依赖:

dependencies:
  pointycastle: ^3.7.3

加密实现:

import 'dart:typed_data';
import 'package:pointycastle/export.dart';

/// Rijndael加密
/// [blockSize] 分组长度,可选16(128位)/24(192位)/32(256位)
Uint8List rijndaelCbcEncrypt(
  Uint8List plainText,
  Uint8List key,
  Uint8List iv,
  int blockSize,
) {
  // 初始化CBC模式Rijndael加密器
  final cipher = CBCBlockCipher(RijndaelEngine(blockSize))
    ..init(true, ParametersWithIV(KeyParameter(key), iv));
  // PKCS7填充
  final paddedText = _pkcs7Pad(plainText, blockSize);
  // 分块加密
  final output = Uint8List(paddedText.length);
  int offset = 0;
  while (offset < paddedText.length) {
    offset += cipher.processBlock(paddedText, offset, output, offset);
  }
  return output;
}

/// PKCS7填充逻辑
Uint8List _pkcs7Pad(Uint8List data, int blockSize) {
  final padLen = blockSize - (data.length % blockSize);
  final padded = Uint8List(data.length + padLen);
  padded.setAll(0, data);
  padded.fillRange(data.length, padded.length, padLen);
  return padded;
}

排查顺序建议

  • 先校验Key、IV字节:找对接方索要可运行的其他语言(Java/PHP/JS)加密示例,将本地转换得到的Key、IV字节数组与示例中的字节数组对比,确保完全一致。
  • 用简单明文验证:使用固定短明文(如test123)、确定的Key和IV加密,先验证简单场景下密文是否匹配,避免长JSON的格式问题干扰排查。
  • 最后校验JSON格式:简单明文验证通过后,再逐字符对比序列化后的JSON字符串与对接方加密用的明文,重点排查键顺序、数字格式、空值、空格换行等细节。

内容的提问来源于stack exchange,提问作者MD MEHEDI HASAN

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 00:15:32