super_cache_secure

AES-256-GCM encrypted in-memory cache for Flutter, built on top of super_cache.

Entries are encrypted individually with a fresh random nonce per write. The MAC is verified on every get() — tampered entries are treated as a cache miss and silently evicted.


Features

  • AES-256-GCM encryption via the cryptography package (hardware-accelerated on device).
  • Key generated once, persisted in iOS Keychain / Android Keystore via flutter_secure_storage.
  • Injected KeyStore interface — swap in an in-memory fake for unit tests without touching flutter_secure_storage.
  • wipeOnEviction: zeroes out the intermediate plaintext buffer after encryption (best-effort under Dart's managed runtime).
  • Full Cache<K,V> compatibility — drop it into a CacheOrchestrator as L2.

Installation

dependencies:
  super_cache: ^1.0.0
  super_cache_secure: ^1.0.0

Quick start

import 'package:super_cache_secure/super_cache_secure_flutter.dart';

final cache = SecureCache<String, String>(
  codec: const StringCodec(),   // your CacheCodec<String>
  keyStore: FlutterSecureKeyStore(),
);
await cache.initialize();       // generates/loads the AES key

await cache.put('token', accessToken);
final token = await cache.get('token');

await cache.dispose();

KeyStore

KeyStore is an abstract interface with three methods:

abstract interface class KeyStore {
  Future<String?> read(String key);
  Future<void> write(String key, String value);
  Future<void> delete(String key);
}

In production, use FlutterSecureKeyStore (imported from super_cache_secure_flutter.dart). In tests, inject a plain Map-backed implementation:

class FakeKeyStore implements KeyStore {
  final _store = <String, String>{};
  @override Future<String?> read(String key) async => _store[key];
  @override Future<void> write(String key, String value) async => _store[key] = value;
  @override Future<void> delete(String key) async => _store.remove(key);
}

final cache = SecureCache<String, MyModel>(
  codec: MyModelCodec(),
  keyStore: FakeKeyStore(),
);

Encryption config

final cache = SecureCache<String, Uint8List>(
  codec: RawBytesCodec(),
  keyStore: FlutterSecureKeyStore(),
  config: const CacheEncryptionConfig(
    keyAlias: 'my_app_cache_key',  // custom key alias
    wipeOnEviction: true,          // zero-fill plaintext after encrypt
  ),
);

Managed-runtime wipe caveat

When wipeOnEviction is true, the code zeroes the Uint8List that held the plaintext immediately after encryption. However, Dart's garbage collector may have already copied the data to another location before the wipe. This provides a best-effort reduction in plaintext exposure time — it is not a cryptographic guarantee. For the highest security requirements, perform encryption at the platform layer.


As L2 in a layered cache

final cache = CacheOrchestrator<String, User>(
  l1: MemoryCache(maxEntries: 50),
  l2: SecureCache(codec: userCodec, keyStore: FlutterSecureKeyStore()),
  l3: DiskCache(directory: cacheDir, codec: userCodec),
);

Barrel files

Import Contents
super_cache_secure.dart SecureCache, KeyStore, CacheEncryptionConfig
super_cache_secure_flutter.dart Above + FlutterSecureKeyStore

Use the plain barrel in dart test (no dart:ui dependency).

Libraries

super_cache_secure
super_cache_secure — AES-256-GCM encrypted in-memory cache.
super_cache_secure_flutter
Flutter-specific extensions for super_cache_secure.