super_cache_secure 1.0.1
super_cache_secure: ^1.0.1 copied to clipboard
AES-256-GCM encrypted in-memory cache for Flutter. Keys stored in iOS Keychain and Android Keystore. Part of the super_cache family.
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
cryptographypackage (hardware-accelerated on device). - Key generated once, persisted in iOS Keychain / Android Keystore via
flutter_secure_storage. - Injected
KeyStoreinterface — swap in an in-memory fake for unit tests without touchingflutter_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 aCacheOrchestratoras 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).