Skip to content

AES Encryption

Encrypting Data with AES in Flutter

AES (Advanced Encryption Standard) is a symmetric encryption algorithm widely used for securing data at rest. In Flutter, you can implement AES encryption using the pointycastle library, which provides cryptographic primitives and supports AES in various modes (e.g., CBC, GCM). This section demonstrates how to encrypt and decrypt data using AES in Flutter.


Prerequisites

Add the following dependencies to your pubspec.yaml:

dependencies:
  flutter: any
  pointycastle: ^3.4.0


Key Concepts

  • Symmetric Encryption: Same key is used for encryption and decryption.
  • AES Key Sizes: 128-bit, 192-bit, or 256-bit (commonly 256-bit for strong security).
  • CBC Mode: Requires an Initialization Vector (IV) for each encryption operation.
  • Padding: AES requires padding (e.g., PKCS7) to handle data that isn't a multiple of the block size.

Example: AES Encryption and Decryption

1. Generate a Secure Key

Use a cryptographically secure random key for production. For simplicity, this example uses a static key (not recommended for real apps):

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

Future<Uint8List> getSecureKey() async {
  // Simulate secure key retrieval from Android Keystore or secure storage
  final key = Uint8List(32);
  final random = Random.secure();
  random.nextBytes(key);
  return key;
}

2. Encrypt Data

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

Future<String> encryptData(String plainText) async {
  final key = await getSecureKey();
  final iv = Uint8List(16);
  final random = Random.secure();
  random.nextBytes(iv);

  final cipher = AESBlockCipher(
    BlockCipherFeedbackModeWithPadding(
      AES().createCipher(),
      PKCS7Padding(),
    ),
  );
  cipher.init(true, KeyParameter(key));

  final input = Uint8List.fromList(plainText.codeUnits);
  final output = Uint8List(input.length);
  int offset = 0;

  while (offset < input.length) {
    final length = cipher.processBlock(input, offset, output, offset);
    offset += length;
  }

  final encrypted = Uint8List(16 + output.length);
  encrypted.setRange(0, 16, iv);
  encrypted.setRange(16, 16 + output.length, output);
  return base64.encode(encrypted);
}

3. Decrypt Data

Future<String> decryptData(String encryptedBase64) async {
  final encrypted = base64.decode(encryptedBase64);
  final iv = Uint8List.fromList(encrypted.sublist(0, 16));
  final ciphertext = Uint8List.fromList(encrypted.sublist(16));

  final key = await getSecureKey();

  final cipher = AESBlockCipher(
    BlockCipherFeedbackModeWithPadding(
      AES().createCipher(),
      PKCS7Padding(),
    ),
  );
  cipher.init(false, KeyParameter(key));

  final output = Uint8List(ciphertext.length);
  int offset = 0;

  while (offset < ciphertext.length) {
    final length = cipher.processBlock(ciphertext, offset, output, offset);
    offset += length;
  }

  // Remove PKCS7 padding
  final paddingLength = output[output.length - 1];
  final plaintext = Uint8List.fromList(output.sublist(0, output.length - paddingLength));
  return String.fromCharCodes(plaintext);
}

Security Considerations

  • Key Management: Never hardcode keys in your app. Use secure storage (e.g., Android Keystore, iOS Keychain) or derive keys from passwords using PBKDF2.
  • IV Handling: Always generate a random IV for each encryption operation and store it alongside the ciphertext.
  • Padding Oracle Attacks: Use secure padding schemes like PKCS7 and avoid predictable IVs.
  • Algorithm Choice: AES is secure, but ensure you use proper modes (e.g., CBC with IV) and avoid ECB mode.

Diagram: AES Encryption Workflow

[Plain Text] → [Padding] → [AES Encryption (CBC)] → [Ciphertext + IV]
[Encrypted Data] → [AES Decryption (CBC)] → [Padding Removal] → [Plain Text]

Key takeaways

  • Use pointycastle for AES encryption in Flutter.
  • Generate secure keys and random IVs for each encryption operation.
  • Store keys in secure storage, not hardcoded in the app.
  • Always use padding schemes like PKCS7 and avoid ECB mode.