Flutter AES加密

2,666 阅读3分钟

引入依赖

encrypt: 5.0.1

核心代码

aes.dart

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

/// AES加密算法
class AES {
  static String encryptAes({
    required String plainText,
    required String keyStr,
    required String ivStr,
    encrypt.AESMode? mode = encrypt.AESMode.cbc,
  }) {
    final key = encrypt.Key.fromUtf8(keyStr);
    final iv = encrypt.IV.fromUtf8(ivStr);
    final encrypter =
        encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc));

    final encrypted = encrypter.encrypt(plainText, iv: iv);
    debugPrint(encrypted.base64); // 加密的结果

    return encrypted.base64;
  }

  static String decryptAes(
      {required String encryptedStr,
      required String keyStr,
      required String ivStr,
      encrypt.AESMode? mode = encrypt.AESMode.cbc}) {
    final key = encrypt.Key.fromUtf8(keyStr);
    final iv = encrypt.IV.fromUtf8(ivStr);

    final encrypter =
        encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc));
    final decrypted = encrypter.decrypt64(encryptedStr, iv: iv);

    return decrypted;
  }
}

测试页面

aes_test_page.dart

import 'dart:math';

import 'package:flutter/material.dart';

import 'aes.dart';

class AesEncryptTestPage extends StatefulWidget {
  const AesEncryptTestPage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<AesEncryptTestPage> createState() => _AesEncryptTestPageState();
}

class _AesEncryptTestPageState extends State<AesEncryptTestPage> {
  String encryptedText = '';
  String decryptedText = '';

  final plainText = '{"a":1}';

  String key = '';

  String iv = '';

  Widget _row(String title, String content) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Text(title),
          const SizedBox(width: 10),
          Text(content),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              _row('加密前:', plainText),
              _row('加密key:', key),
              _row('加密iv:', iv),
              _row('加密后:', encryptedText),
              _row('解密后', decryptedText),
            ],
          ),
        ),
        floatingActionButton: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            FloatingActionButton(
              onPressed: () {
                key = getRandomString(16);
                iv = getRandomString(16);
                setState(() {});
              },
              tooltip: '随机生成key和Iv',
              child: const Icon(Icons.add),
            ),
            FloatingActionButton(
              onPressed: () {
                encryptedText = AES.encryptAes(
                    plainText: plainText, keyStr: key, ivStr: iv);
                setState(() {});
              },
              tooltip: '触发加密',
              child: const Icon(Icons.add),
            ),
            FloatingActionButton(
              onPressed: () {
                decryptedText = AES.decryptAes(
                    encryptedStr: encryptedText, keyStr: key, ivStr: iv);
                setState(() {});
              },
              tooltip: '触发解密',
              child: const Icon(Icons.seven_k),
            ),
          ],
        ) // This trailing comma makes auto-formatting nicer for build methods.
        );
  }

  /// AES加密测试
  String getRandomString(int length) {
    Random random = Random();
    List<String> digits =
        List.generate(length, (_) => random.nextInt(10).toString());
    return digits.join();
  }
}

要素讲解

AES加密是典型的对称算法加密,支持正向加密和逆向解密,该算法主要有4个要素:

当使用AES加密算法进行加密或解密时,有四个要素是必须考虑的。

  1. 加密或解密的字符串(Plaintext or Ciphertext):这是要进行加密或解密操作的实际字符串。对于加密操作,这个字符串是明文(Plaintext),它将被转换为加密后的密文(Ciphertext)。对于解密操作,这个字符串是密文(Ciphertext),它将被还原为原始的明文。

  2. 加密密钥(Encryption Key):加密密钥是用于进行AES加密和解密的关键组成部分。它是一个固定长度的二进制值,如128位、192位或256位。密钥长度的选择取决于所使用的AES算法变体(例如AES-128、AES-192或AES-256)。密钥必须保密,并且加密和解密操作必须使用相同的密钥。

  3. 初始化向量(Initialization Vector, IV):初始化向量是一个固定长度的随机值,它被用作AES加密算法的额外输入。它的长度通常与AES区块大小相同,即128位。如果使用相同的密钥对不同的明文进行加密,则每个明文都需要使用不同的IV。IV的作用是确保相同的明文在不同加密过程中生成的密文是不同的,增加了密码的安全性。

  4. 加密模式(Encryption Mode):加密模式决定了AES算法如何处理长度超过一个区块大小的数据。常见的加密模式包括ECB、CBC、CFB和OFB等。以下是一些常用的加密模式:

    • 电子密码本模式(Electronic Codebook Mode, ECB):每个明文块都被独立加密,相同的明文块将生成相同的密文块。
    • 密码分组链接模式(Cipher Block Chaining Mode, CBC):每个明文块在加密之前都会与前一个密文块进行异或操作,增加了加密过程的随机性。
    • 密文反馈模式(Cipher Feedback Mode, CFB):使用前一次加密的密文作为下一次加密的输入,可以支持加密和解密过程的流式处理。
    • 输出反馈模式(Output Feedback Mode, OFB):将前一次的输出作为下一次的输入,可以支持加密和解密过程的流式处理。

选择适当的加密模式以及正确使用加密密钥和初始化向量(IV)是确保AES算法安全和可靠运行的重要因素。