SecurePrefsPlus

A secure storage solution combining SharedPreferences with AES-256-GCM encryption for Flutter. Pure Dart implementation with full cross-platform support including web.

Features

Military-grade encryption - AES-256-GCM encryption
Pure Dart - No native dependencies, works everywhere
Cross-platform - iOS, Android, Web, Windows, macOS, Linux
Simple API - Familiar SharedPreferences-like interface
Type-safe - Support for String, int, double, bool, and List

Installation

Add to your pubspec.yaml:

dependencies:
  secure_prefs_plus: ^1.0.0

Then run:

flutter pub get

Usage

Basic Example

import 'package:secure_prefs_plus/secure_prefs_plus.dart';

// Initialize with your encryption key
final prefs = await SecurePrefsPlus.getInstance(
  encryptionKey: 'your-secret-encryption-key',
);

// Store encrypted data
await prefs.setString('username', 'john_doe');
await prefs.setInt('age', 25);
await prefs.setBool('isLoggedIn', true);
await prefs.setDouble('balance', 1234.56);
await prefs.setStringList('tags', ['flutter', 'dart', 'security']);

// Retrieve encrypted data
String? username = prefs.getString('username');
int? age = prefs.getInt('age');
bool? isLoggedIn = prefs.getBool('isLoggedIn');
double? balance = prefs.getDouble('balance');
List<String>? tags = prefs.getStringList('tags');

// Check if key exists
if (prefs.containsKey('username')) {
  print('Username exists!');
}

// Remove a key
await prefs.remove('username');

// Get all keys
Set<String> keys = prefs.getKeys();

// Clear all data
await prefs.clear();

Advanced Usage

Custom Salt for Key Derivation

final prefs = await SecurePrefsPlus.getInstance(
  encryptionKey: 'my-password',
  salt: 'custom-salt-for-kdf',
);

Storing Sensitive Tokens

// Perfect for storing API tokens, session data, etc.
await prefs.setString('auth_token', 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...');
await prefs.setString('refresh_token', 'refresh_token_here');

// Retrieve when needed
String? token = prefs.getString('auth_token');

User Settings with Encryption

class UserSettings {
  final SecurePrefsPlus _prefs;

  UserSettings(this._prefs);

  Future<void> saveUserData({
    required String email,
    required String apiKey,
  }) async {
    await _prefs.setString('user_email', email);
    await _prefs.setString('api_key', apiKey);
  }

  String? getUserEmail() => _prefs.getString('user_email');
  String? getApiKey() => _prefs.getString('api_key');
}

Security Features

AES-256-GCM Encryption

SecurePrefsPlus uses AES-256 in GCM (Galois/Counter Mode) which provides:

  • Confidentiality - Data is encrypted with 256-bit keys
  • Integrity - Built-in authentication prevents tampering
  • Performance - Fast encryption/decryption even on mobile devices

Key Derivation

Your encryption key is processed using PBKDF2 with SHA-256:

  • 10,000 iterations - Protects against brute-force attacks
  • Custom salt support - Add your own salt for additional security
  • Deterministic - Same key always produces same encryption

No Plain Text Storage

All data is encrypted before being stored in SharedPreferences. Even if someone gains access to the device storage, they cannot read your data without the encryption key.

Platform Support

Platform Supported Notes
iOS Fully supported
Android Fully supported
Web Uses localStorage with encryption
Windows Fully supported
macOS Fully supported
Linux Fully supported

Best Practices

1. Secure Your Encryption Key

// ❌ BAD - Hardcoded key
final prefs = await SecurePrefsPlus.getInstance(
  encryptionKey: 'hardcoded-key-123',
);

// ✅ GOOD - Use environment variables or secure key storage
final encryptionKey = const String.fromEnvironment('ENCRYPTION_KEY');
final prefs = await SecurePrefsPlus.getInstance(
  encryptionKey: encryptionKey,
);

2. Different Keys for Different Users

// Use user-specific keys
final userId = getCurrentUserId();
final prefs = await SecurePrefsPlus.getInstance(
  encryptionKey: 'base-key',
  salt: 'user-$userId',
);

3. Handle Exceptions

try {
  final value = prefs.getString('sensitive_data');
  print(value);
} on EncryptionException catch (e) {
  print('Decryption failed: $e');
  // Handle corrupted data or wrong key
}

4. Clear Data on Logout

Future<void> logout() async {
  final prefs = await SecurePrefsPlus.getInstance(
    encryptionKey: userEncryptionKey,
  );
  await prefs.clear();
}

API Reference

Initialization

static Future<SecurePrefsPlus> getInstance({
  String encryptionKey = 'default_key_change_me',
  String? salt,
})

Storage Methods

Future<bool> setString(String key, String value)
String? getString(String key)

Future<bool> setInt(String key, int value)
int? getInt(String key)

Future<bool> setDouble(String key, double value)
double? getDouble(String key)

Future<bool> setBool(String key, bool value)
bool? getBool(String key)

Future<bool> setStringList(String key, List<String> value)
List<String>? getStringList(String key)

Management Methods

Future<bool> remove(String key)
bool containsKey(String key)
Future<bool> clear()
Set<String> getKeys()
Future<void> reload()

Performance

Encryption/decryption is fast enough for typical mobile use cases:

  • String (100 chars): ~1-2ms
  • Int/Double/Bool: ~1ms
  • List: ~2-3ms

Benchmarks on iPhone 12 Pro

Comparison with Alternatives

Feature SecurePrefsPlus flutter_secure_storage encrypted_shared_preferences
Pure Dart ❌ (Native) ❌ (Native)
Web Support
Type Safety ⚠️ (String only)
Setup Required ✅ (iOS Keychain) ✅ (Android)
Encryption AES-256-GCM Platform-dependent AES-256-CBC

Limitations

  • Not for large data - Designed for preferences and tokens, not large files
  • Key management - You're responsible for managing encryption keys securely
  • No biometric - Doesn't integrate with device biometrics (use flutter_secure_storage for that)

Contributing

Contributions are welcome! Please read our Contributing Guide first.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

Changelog

See CHANGELOG.md for version history.


Made with ❤️ for the Flutter community