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

Flutter端AES-256加密实现(适配Java后端解密)

Flutter端适配Java AES加解密的加密实现

实现说明

  • 现有两端解密逻辑的核心参数已经完全对齐,只需要按照Java端加密的输出格式补全Flutter加密逻辑即可实现双向互通
  • 加密逻辑完全对齐Java端规则:20字节随机盐 + 16字节随机IV + AES/CBC模式加密 + 密钥通过PBKDF2WithHmacSHA1派生(迭代次数65556,密钥长度256位)
  • 填充规则使用PKCS7Padding,和Java端的PKCS5Padding在AES块大小为16字节的场景下完全兼容
  • 随机数使用Dart安全随机生成器,和Java端SecureRandom安全等级一致
  • 最终输出为「盐+IV+密文」拼接后的Base64字符串,和Java端加密输出格式完全一致,Java端无需修改任何代码即可正常解密

前置依赖

现有解密逻辑已经依赖pointycastle加密库,确保项目中已经引入该依赖即可,无需额外引入其他包。

完整实现代码

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

class EncryptionHelper {
  /// 加密方法,输出密文可直接被Java端decrypt方法解密
  static String encrypt(String plaintext, {String password = "Hello"}) {
    final secureRandom = Random.secure();
    // 生成20字节随机盐,和Java端盐长度一致
    final saltBytes = Uint8List.fromList(
      List.generate(20, (_) => secureRandom.nextInt(256))
    );
    // 生成16字节IV,对应AES块大小
    final ivBytes = Uint8List.fromList(
      List.generate(16, (_) => secureRandom.nextInt(256))
    );

    // 复用现有密钥生成逻辑,派生256位AES密钥
    final key = generateKey(password, saltBytes);

    // 初始化AES/CBC/PKCS7加密器
    final cipher = CBCBlockCipher(AESFastEngine());
    final cipherParams = ParametersWithIV<KeyParameter>(
      KeyParameter(key), 
      ivBytes
    );
    final paddingParams = PaddedBlockCipherParameters<
      ParametersWithIV<KeyParameter>, 
      Null
    >(cipherParams, null);
    final paddedCipher = PaddedBlockCipherImpl(PKCS7Padding(), cipher);
    // 传入true表示初始化为加密模式
    paddedCipher.init(true, paddingParams);

    // 明文转UTF-8字节数组后执行加密
    final plainBytes = Uint8List.fromList(utf8.encode(plaintext));
    final encryptedBytes = paddedCipher.process(plainBytes);

    // 按 盐 + IV + 密文 的顺序拼接字节数组,和Java端拼接逻辑完全一致
    final resultBuffer = Uint8List(
      saltBytes.length + ivBytes.length + encryptedBytes.length
    );
    resultBuffer.setAll(0, saltBytes);
    resultBuffer.setAll(saltBytes.length, ivBytes);
    resultBuffer.setAll(saltBytes.length + ivBytes.length, encryptedBytes);

    // 最终Base64编码返回
    return base64.encode(resultBuffer);
  }

  /// 原有解密方法,无需修改
  static String decrypt(
    String ciphertext,
  ) {
    Uint8List ciphertextlist = base64.decode(ciphertext);
    var salt = ciphertextlist.sublist(0, 20);
    var iv = ciphertextlist.sublist(20, 20 + 16);
    var encrypted = ciphertextlist.sublist(20 + 16);

    Uint8List key = generateKey("Hello", salt);
    CBCBlockCipher cipher = new CBCBlockCipher(new AESFastEngine());

    ParametersWithIV<KeyParameter> params =
        new ParametersWithIV<KeyParameter>(new KeyParameter(key), iv);

    PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>
        paddingParams =
        new PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>(
            params, null);
    PaddedBlockCipherImpl paddingCipher =
        new PaddedBlockCipherImpl(new PKCS7Padding(), cipher);
    paddingCipher.init(false, paddingParams);
    var val = paddingCipher.process(encrypted);

    return new String.fromCharCodes(val);
  }

  /// 原有密钥生成方法,无需修改
  static Uint8List generateKey(String passphrase, Uint8List salt) {
    Uint8List passphraseInt8List = Uint8List.fromList(passphrase.codeUnits);

    KeyDerivator derivator =
        PBKDF2KeyDerivator(HMac(SHA1Digest(), 64)); // 64 byte block size
    Pbkdf2Parameters params =
        Pbkdf2Parameters(salt, 65556, 32); // 32 byte key size
    derivator.init(params);
    return derivator.process(passphraseInt8List);
  }
}

验证说明

  • 该方法加密输出的密文,可以直接传入现有Java端decrypt方法解密得到正确明文
  • 该方法加密输出的密文,也可以直接传入现有Flutter端decrypt方法解密得到正确明文
  • 两端加解密完全双向互通,不需要修改现有Java端和Flutter端的原有解密逻辑

内容的提问来源于stack exchange,提问作者yong ho

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 23:30:52