flutter:encrypt加密库

是什么

encrypt 是一个 Dart/Flutter 的加密库,主要提供了对常见对称加密(AES)、非对称加密(RSA)、以及编码(Base64)等的支持。

  • 对称加密:加密和解密用同一把密钥(例如 AES)。
  • 非对称加密:加密和解密用不同的密钥(例如 RSA)。
  • 编码:Base64、Hex 这些只是编码,不是真正的加密。

encrypt 库主要基于 pointycastle 这个更底层的 Dart 加密库,提供了更易用的 API。

基本使用

安装

flutter pub add encrypt

AES 加解密(对称)

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

void main() {
  // 密钥和初始向量(IV)
  // Key 必须 16/24/32 长度
  final key = encrypt.Key.fromUtf8('1234567890123456');
  final iv = encrypt.IV.fromLength(16);
  print(key.bytes);// [49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50, 51, 52, 53, 54]
  print(iv.bytes); // [144, 201, 60, 163, 168, 140, 144, 216, 131, 86, 191, 37, 96, 76, 58, 35]

  // AES 加密器
  final encrypter = encrypt.Encrypter(encrypt.AES(key));

  // 加密
  final encrypted = encrypter.encrypt('hello flutter', iv: iv);
  // 输出加密后的 Base64 字符串
  print(encrypted.base64); //ksLEH/Cge3qzTGkdBehNxw==

  // 解密
  final decrypted = encrypter.decrypt(encrypted, iv: iv);
  print(decrypted); // hello flutter
}

fromUtf8(key)

Key.fromUtf8() 的参数长度必须是 16 / 24 / 32 个字节,这是 AES 算法本身的要求,不是 Flutter 特有的。

final key = Key.fromUtf8('1234567890123456'); // ✅ 16 字节,AES-128
final key = Key.fromUtf8('123456789012345678901234'); // ✅ 24 字节,AES-192
final key = Key.fromUtf8('12345678901234567890123456789012'); // ✅ 32 字节,AES-256

但如果是其他长度(比如 10、20、30),会直接报错:

Invalid argument(s): Key length must be 16/24/32 bytes

fromUtf8 是把字符串按 UTF-8 编码转成字节,所以要确保你的字符串长度刚好是 16/24/32 个 ASCII 字符(因为一个 ASCII 字符占一个字节)。

  • 如果包含中文、emoji 之类的多字节字符,长度可能对不上。
  • 推荐只用 ASCII(字母、数字、符号)来做 key。

如果你需要随机 key,可以用:

final key = Key.fromSecureRandom(32); // 生成 32 字节随机 key

AES(...)

AES(
  Key key,                  // 必填,加密用的 key,长度必须 16/24/32 字节
  { 
    AESMode mode = AESMode.sic,  // 可选,加密模式,默认是 sic
    String? padding = 'PKCS7'    // 可选,填充方式,默认是 PKCS7
  }
)
  1. key(必须)

    • 类型:Key

    • 作用:AES 加密/解密的密钥

    • 长度要求:16 / 24 / 32 字节(AES-128 / AES-192 / AES-256)

  2. mode(可选)

    • 类型:AESMode

    • 默认:AESMode.sic

    • 可选值:

      • AESMode.cbc → 常见,需 IV,安全性高
      • AESMode.ecb → 不推荐,模式弱,无 IV
      • AESMode.sic → 类似 CTR,常用
      • AESMode.cfb / AESMode.ofb → 流模式
      • AESMode.gcm → 带认证的模式,常用在网络通信
  3. padding(可选)

    • 类型:String?

    • 默认:PKCS7

    • 作用:当数据长度不是 16 字节的整数倍时,需要填充

    • 常用值:

      • 'PKCS7' → 最常见
      • null → 不填充(通常在流模式/分组对齐时用)

IV 的作用

  • IV(初始化向量, Initialization Vector)是 分组加密算法(比如 AES)在某些模式下必需的一个额外参数
  • 保证加密结果不一样:如果你用同一个 key 去加密同一份明文,没有 IV 的话,密文每次都是一样的。有了随机的 IV,即使明文和 key 都一样,密文也会不一样,增加安全性。
  • 防止模式漏洞:在 CBC、CFB、OFB、CTR(SIC) 等模式下,第一块数据的加密需要一个“起始块”。如果没有 IV,就会默认用固定值(比如全 0),这样会泄露数据规律。
  • 增加随机性,但不增加安全强度:IV 不需要保密(可以明文传输),但必须随机或唯一。真正控制安全的是 key,IV 只是用来避免“重复密文”的。

fromLength的作用

final iv = IV.fromLength(16);
// [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

fromLength(n) 会创建一个 长度为 n 的 IV,内容全是 0。一般在以下情况中使用:

  • 调试/测试:用固定的全 0 IV,可以让你每次加密的结果一致,方便对比和验证。

  • 不关心安全性时(例如课堂示例、简单本地存储)只是演示 AES 的功能,可以用全 0 IV。

  • 但不推荐在生产环境中使用 。因为 IV 全 0 就失去了“随机性”的意义,容易被攻击者推测出数据模式。

Key和IV底层都是一个List

/// Represents an Encryption Key.
class Key extends Encrypted {

  Key(Uint8List bytes) : super(bytes);
 
  Key.fromBase64(String encoded) : super.fromBase64(encoded);


  Key.fromUtf8(String input) : super.fromUtf8(input);
}

/// Represents an Initialization Vector.
class IV extends Encrypted {
  IV(Uint8List bytes) : super(bytes);
  IV.fromLength(int length) : super.fromLength(length);
}

class Encrypted {
  
  Encrypted(this._bytes);

  final Uint8List _bytes;
  
  /// Gets the Encrypted bytes.
  Uint8List get bytes => _bytes;
    /// Creates an Encrypted object from a UTF-8 string.
  Encrypted.fromUtf8(String input)
      : _bytes = Uint8List.fromList(convert.utf8.encode(input));
  
  Encrypted.fromLength(int length) : _bytes = SecureRandom(length).bytes;
}

RSA 加解密(非对称)

import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:pointycastle/asymmetric/api.dart';

void main() {
  // 模拟一对 RSA 公钥和私钥(通常是从文件/服务端获取)
  final publicKey = encrypt.RSAKeyParser().parse('-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----') as RSAPublicKey;
  final privateKey = encrypt.RSAKeyParser().parse('-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----') as RSAPrivateKey;
	// 同时传公钥 + 私钥(支持加解密)
  final encrypter = encrypt.Encrypter(encrypt.RSA(publicKey: publicKey, privateKey: privateKey));

  // 加密
  final encrypted = encrypter.encrypt('hello flutter');
  print(encrypted.base64);

  // 解密
  final decrypted = encrypter.decrypt(encrypted);
  print(decrypted);
}

RSA

class RSA extends AbstractRSA implements Algorithm {
  RSA(
      {RSAPublicKey? publicKey,
      RSAPrivateKey? privateKey,
      RSAEncoding encoding = RSAEncoding.PKCS1,
      RSADigest digest = RSADigest.SHA1})
      : super(
          publicKey: publicKey,
          privateKey: privateKey,
          encoding: encoding,
          digest: digest,
        );
}

参数解析

publicKey公钥(加密/验证签名)

  • 类型:RSAPublicKey?
  • 作用:加密数据 / 验证签名
  • Flutter 端一般只需要传公钥(用来加密),私钥放在服务端。

privateKey私钥(解密/生成签名)

  • 类型:RSAPrivateKey?
  • 作用:解密数据 / 生成签名
  • 如果你只需要加密,可以不传私钥。
  • 如果你要做解密,就必须传入私钥。

encoding填充方式(默认 OAEP,更安全)

  • 类型:RSAEncoding(枚举)

  • 默认值:RSAEncoding.OAEP(更安全的填充方式)

  • 可选值:

    • RSAEncoding.PKCS1 → 传统 PKCS#1 填充
    • RSAEncoding.OAEP → 更现代,推荐
  • RSA 本身不能直接加密长数据,所以需要填充(padding)方式。

加密(只用公钥)

final publicKey = RSAKeyParser().parse(publicPem) as RSAPublicKey;

final encrypter = Encrypter(RSA(publicKey: publicKey));

final encrypted = encrypter.encrypt('hello flutter');
print(encrypted.base64);

解密(只用私钥)

final privateKey = RSAKeyParser().parse(privatePem) as RSAPrivateKey;

final encrypter = Encrypter(RSA(privateKey: privateKey));

final decrypted = encrypter.decrypt(encrypted);
print(decrypted); // hello flutter

同时传公钥 + 私钥(支持加解密)

final encrypter = Encrypter(RSA(
  publicKey: publicKey,
  privateKey: privateKey,
  encoding: RSAEncoding.OAEP,
));

使用OpenSSL获取公钥和私钥

  1. 生成 RSA 私钥

    openssl genrsa -out private.pem 2048
    
    • private.pem 就是私钥文件
    • 2048 是密钥长度(常用 2048 或 4096)
  2. 从私钥导出公钥

    openssl rsa -in private.pem -pubout -out public.pem
    
    • public.pem 就是公钥文件
    • 默认就是 PEM 格式(-----BEGIN PUBLIC KEY-----
  3. 在服务端(Linux/Mac/Windows)可以用 OpenSSL 。如果没有这个命令,就需要去下载。

案例: RSA + AES 混合加密

完整示例代码


import 'package:encrypt/encrypt.dart';
import 'dart:typed_data';
import 'package:pointycastle/asymmetric/api.dart';

void main() {
  // ============= 1. 生成 RSA 公钥和私钥(实际一般是后端生成) =============
  final rsaPublicKeyPem = '''
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlqOzzCwejyWdahzqw/4N
flxlQWn/LEERkEQuHFjbT4T5ixEFsAoZIsVSoZ9paWyDC/Cvt5m7ex9jibxXE3tO
Oq12BKplf9Oi6eDAlnVeVQOm5u/uQ9y1uH05pC5lZfLKSmjm9YLKbBBTBuoHk1Xi
/wnJ5X7jlreQ97b6TOwi6NAH4BhPG830LV1AuCnWJPq4wHsXLOxx3bwBObSFEOPk
FCo592jLdvsq2YTH31AQodq03vvFUUgCABv4YXg87FkCahU7cIl4MGu844CXy2ze
5ErqxkTxD4KkBXVWkBb5cK+ydR/F/7p0tFmUWmcuCDKaT24p3/6rzlEAnG8zGzvS
PQIDAQAB
-----END PUBLIC KEY-----

''';

  final rsaPrivateKeyPem = '''
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCWo7PMLB6PJZ1q
HOrD/g1+XGVBaf8sQRGQRC4cWNtPhPmLEQWwChkixVKhn2lpbIML8K+3mbt7H2OJ
vFcTe046rXYEqmV/06Lp4MCWdV5VA6bm7+5D3LW4fTmkLmVl8spKaOb1gspsEFMG
6geTVeL/CcnlfuOWt5D3tvpM7CLo0AfgGE8bzfQtXUC4KdYk+rjAexcs7HHdvAE5
tIUQ4+QUKjn3aMt2+yrZhMffUBCh2rTe+8VRSAIAG/hheDzsWQJqFTtwiXgwa7zj
gJfLbN7kSurGRPEPgqQFdVaQFvlwr7J1H8X/unS0WZRaZy4IMppPbinf/qvOUQCc
bzMbO9I9AgMBAAECggEAEeeML8jQqwf4AUxFlR0Foo691DwSgcKMIV8RMfpXushd
1qsjx2wz15+ndiFZ6Jdmrg0h/YsOrxAohw71NJIT1sKWQ/Cy1rIja3P0wA1cNHOW
K126LqO1j6OGrd5729WzOIvmY6jzgUuharF3TApJzDFwJ1BhIaFY4DCF6I2qiow8
qAIOa+pAvMMSF9fE7hLsfUQm7nH/kYHTL/pCDjl6HyR0G3yY6mx+u9vM2Rgur+yP
PbCalv05qZZn/0jgvdURTdPI3SZ2E5OZ5MRo3m6KsV3d7D/EvxVSry2FvDti8Gw5
zj5djF1+UnLdp7PnQug51LOSDsISSEOAmBfZyyk5EQKBgQDKBlIbYZydNZGn+qjT
CtFUm99l1w9dZ4Ki797pBlTbxxeT7cM+aZPRII/oHs4nd/TN39Gtk853jOuvEl4Z
jRZbFa5/7oUpfpra+4RoM+kNc1weTrEY2X+M0xz4ns+Wsdfa4gTJTWKfs2GU30nb
Q2zn99xDApOrkaB+aIn44ZS4mQKBgQC+4taBWtR1e32dA/hzObd2o72m5cwON6L9
Psssg+knEzIPH+wZL92G5l/f+BSs731BankS8FbMPCNNT+2F/glIoiPUeIZQG0Xq
MUN3D7yz8rKD5d2HCjeujiVlhqDz9vRLozQaRHEl72V3kQRY53YfjdU3fN+exAAx
obLIpOw5RQKBgQCisZhp6KAhksRsTNasrqeJxcWQ1DLRe8yevyH681hfbeQ1A2Ma
3hdmcRyzSCupaVdCfJ71dHTvnhMneFlDpnV8gOd4q3OdyRGYjLlC2Zszc9WZqrHA
W1f25wULy4lNyIcXBLHqE2H7TpClPXTTGWeZH+jIJkkaADsJ0dJbFf+Y8QKBgFWS
FLzqPeHomRgBRqhI0GDD6GngDAi3kj5anvP2sldM+JzlH47u8SzfK02YxZP8zDa+
B0ahLRfjQaQP15fAmOLRpKRD31obz8y7htXh3SMCAlq0eglmYC3FFSidIJwdMciS
gfHgiqSJ2/+sp7k/Ean1iAaW2RwwGzIknaPqoubNAoGAUlQB2u5mva1bCAiIr5ek
2jVCjnVj7j0/ry10ztZS6N+k1arvTCELr4CrxYzeF0gVCB25q6tFCNte1snanOzS
exWVNY5R8mVcLGqPyKYFTiqxMApLZgjQFFjb1G80ScUBaTZsHG8EJR0+5nBB8cfX
y1RIA+Fk1nyBUMSmBoPHLHs=
-----END PRIVATE KEY-----
''';

  final publicKey = RSAKeyParser().parse(rsaPublicKeyPem) as RSAPublicKey;
  final privateKey = RSAKeyParser().parse(rsaPrivateKeyPem) as RSAPrivateKey;

  // ============= 2. 前端:生成 AES key,用 RSA 公钥加密后传给后端 =============
  final aesKey = Key.fromUtf8(
    'my32lengthsupersecretnooneknows!',
  ); // 32 字节 AES 密钥
  final iv = IV.fromLength(16); // 初始化向量

  final rsaEncrypter = Encrypter(RSA(publicKey: publicKey));
  final encryptedAesKey = rsaEncrypter.encryptBytes(aesKey.bytes);
  print('🔐 发送给后端的 被RSA 加密的 Key(Base64):${encryptedAesKey.base64}');

  // ============= 3. 前端:用 AES 加密实际数据 =============
  final aesEncrypter = Encrypter(AES(aesKey));
  final encryptedData = aesEncrypter.encrypt(
    'Hello Hybrid Encryption!',
    iv: iv,
  );
  print('📦 发送给后端的密文(Base64):${encryptedData.base64}');

  // ============= 4. 后端:用 RSA 私钥解密 AES Key =============
  final rsaDecrypter = Encrypter(RSA(privateKey: privateKey));
  final decryptedAesKeyBytes = rsaDecrypter.decryptBytes(encryptedAesKey);
  // Uint8List.fromList:把 List<int> -> Uint8List
  final decryptedAesKey = Key(Uint8List.fromList(decryptedAesKeyBytes));

  // ============= 5. 后端:用解密出来的 AES Key 解密数据 =============
  final aesDecrypter = Encrypter(AES(decryptedAesKey));
  final decryptedText = aesDecrypter.decrypt(encryptedData, iv: iv);
  print('✅ 解密得到明文:$decryptedText');
}

执行效果(输出示例)

🔐 发送给后端的 AES Key(Base64):RrUeJ9d2...
📦 发送给后端的密文(Base64):3fQ2J6Gm...
✅ 解密得到明文:Hello Hybrid Encryption!

流程图

前端 (Flutter)                                   后端 (Server)
────────────────────────────────────────────────────────────────────

生成随机 AES Key ──────┐
                      │
明文数据 ──(AES 加密)──┼───► 密文数据 ────────────────►
                      │
RSA 公钥加密 AES Key ──┘                           │
                                                  │
                                  RSA 私钥解密 AES Key ◄─── 加密后的 AES Key
                                                  │
                               (AES 解密密文数据) ◄─── 密文数据
                                                  │
                                            得到明文数据
  • AES → 用来加密大数据(快)
  • RSA → 只加密 AES Key(保证安全)
  • 两者结合就是 混合加密

×

喜欢就点赞,疼爱就打赏