secure_db 1.0.4
secure_db: ^1.0.4 copied to clipboard
A unified secure database package that provides encrypted storage using both Hive and SQLite with automatic encryption/decryption.
SecureDB #
A unified secure database package for Flutter that provides encrypted storage using both Hive and SQLite with automatic encryption/decryption. Choose the storage solution that fits your needs while maintaining consistent security across your app.
๐ Features #
- ๐ Dual Storage Options: Support for both Hive (NoSQL) and SQLite (SQL)
- ๐ก๏ธ Automatic Encryption: All data encrypted with AES-256-GCM before storage
- ๐ Secure Key Management: Platform-specific secure storage (Keychain/Keystore)
- ๐ฏ Type Safety: Full generic type support for both storage systems
- ๐ Easy Migration: Simple migration from existing Hive or SQLite implementations
- ๐ฑ Cross-Platform: Works on iOS, Android, macOS, Windows, and Linux
- โก Performance: Optimized for both small key-value pairs and complex queries
- ๐ ๏ธ Developer Friendly: Intuitive APIs that mirror native Hive and SQLite
๐ฆ Installation #
Add this to your package's pubspec.yaml
file:
dependencies:
secure_db: ^1.0.4
Then run:
flutter pub get
๐ Quick Start #
Initialize SecureDB #
import 'package:secure_db/secure_db.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize SecureDB with both Hive and SQLite support
await SecureDB.init();
runApp(MyApp());
}
Simple Key-Value Storage (Quick API) #
// Store different types of data
await SecureDB.setString('username', 'john_doe');
await SecureDB.setInt('user_id', 12345);
await SecureDB.setBool('is_premium', true);
await SecureDB.setMap('user_profile', {
'name': 'John Doe',
'email': 'john@example.com',
'preferences': {'theme': 'dark'}
});
// Retrieve data
String? username = await SecureDB.getString('username');
int? userId = await SecureDB.getInt('user_id');
bool? isPremium = await SecureDB.getBool('is_premium');
Map<String, dynamic>? profile = await SecureDB.getMap('user_profile');
print('User: $username ($userId) - Premium: $isPremium');
๐ Usage Guide #
๐๏ธ Hive Storage (NoSQL) #
Perfect for simple key-value storage, user preferences, and small datasets.
// Method 1: Through SecureDB factory (recommended)
final userBox = await SecureDB.hive().openBox<Map<String, dynamic>>('users');
// Method 2: Direct instance access
final userBox = await SecureHive.instance.openBox<Map<String, dynamic>>('users');
// Store user data with automatic encryption
await userBox.put('user_123', {
'name': 'John Doe',
'email': 'john@example.com',
'created_at': DateTime.now().toIso8601String(),
'settings': {
'theme': 'dark',
'notifications': true,
}
});
// Retrieve user data (automatically decrypted)
Map<String, dynamic>? user = userBox.get('user_123');
print('User: ${user?['name']}');
// Batch operations
await userBox.putAll({
'user_124': {'name': 'Jane Smith', 'email': 'jane@example.com'},
'user_125': {'name': 'Bob Wilson', 'email': 'bob@example.com'},
});
// Listen to changes
userBox.watch().listen((BoxEvent event) {
print('User ${event.key} was ${event.deleted ? 'deleted' : 'updated'}');
});
// Additional operations via instance
await SecureHive.instance.closeBox('users');
await SecureHive.instance.deleteBox('users');
bool exists = await SecureHive.instance.boxExists('users');
๐๏ธ SQLite Storage (SQL) #
Ideal for complex data relationships, queries, and larger datasets.
// Method 1: Through SecureDB factory (recommended)
final db = await SecureDB.sqlite().openDatabase(
'app_database.db',
version: 1,
onCreate: (db, version) async {
// Create tables with encrypted columns
await db.createTable(
'users',
{
'id': 'INTEGER PRIMARY KEY',
'email': 'TEXT UNIQUE',
'profile_data': 'TEXT', // This will be encrypted
'created_at': 'INTEGER',
},
encryptedColumns: ['profile_data'], // Specify which columns to encrypt
);
},
);
// Method 2: Direct instance access
final db = await SecureSQLite.instance.openDatabase(
'app_database.db',
version: 1,
onCreate: (db, version) async {
// Same configuration as above
},
);
// Insert encrypted data
await db.insert(
'users',
{
'email': 'john@example.com',
'profile_data': jsonEncode({
'name': 'John Doe',
'phone': '+1234567890',
'ssn': '123-45-6789', // Sensitive data automatically encrypted
}),
'created_at': DateTime.now().millisecondsSinceEpoch,
},
encryptedColumns: ['profile_data'],
);
// Query with automatic decryption
final users = await db.query(
'users',
where: 'email = ?',
whereArgs: ['john@example.com'],
encryptedColumns: ['profile_data'],
);
for (final user in users) {
print('User: ${user['email']}');
final profileData = jsonDecode(user['profile_data'] as String);
print('Name: ${profileData['name']}');
}
// Additional operations via instance
await SecureSQLite.instance.closeDatabase('app_database.db');
await SecureSQLite.instance.deleteDatabase('app_database.db');
bool exists = await SecureSQLite.instance.databaseExists('app_database.db');
๐ Advanced SQLite Operations #
// Complex queries with joins
final result = await db.rawQuery('''
SELECT u.email, p.title, p.content
FROM users u
JOIN posts p ON u.id = p.user_id
WHERE u.created_at > ?
ORDER BY p.created_at DESC
LIMIT 10
''', [DateTime.now().subtract(Duration(days: 30)).millisecondsSinceEpoch]);
// Transactions for data integrity
await db.transaction((txn) async {
await txn.insert('users', userData, encryptedColumns: ['profile_data']);
await txn.insert('user_settings', settingsData, encryptedColumns: ['preferences']);
await txn.insert('audit_log', logData);
});
// Batch operations for performance
await db.batch([
BatchOperation.insert('posts', post1Data, encryptedColumns: ['content']),
BatchOperation.insert('posts', post2Data, encryptedColumns: ['content']),
BatchOperation.update('users', updateData, where: 'id = ?', whereArgs: [userId]),
]);
๐ง Configuration #
// Custom configuration
await SecureDB.init(config: DbConfig(
enableLogging: true,
databasePath: '/custom/path',
enableWalMode: true,
maxConnections: 5,
));
// Development vs Production
await SecureDB.init(config: DbConfig.development); // Enables logging
await SecureDB.init(config: DbConfig.production); // Optimized for production
๐ Custom Encryption Keys #
// Use your own encryption key
final customKey = 'your-base64-encoded-256-bit-key';
// For Hive
final box = await SecureDB.hive().openBox<String>(
'secure_box',
encryptionKey: customKey,
);
// Or via instance
final box = await SecureHive.instance.openBox<String>(
'secure_box',
encryptionKey: customKey,
);
// For SQLite
final db = await SecureDB.sqlite().openDatabase(
'secure_db.db',
encryptionKey: customKey,
);
// Or via instance
final db = await SecureSQLite.instance.openDatabase(
'secure_db.db',
encryptionKey: customKey,
);
๐ฏ When to Use What #
Use Hive when: #
- โ Simple key-value storage
- โ User preferences and settings
- โ Caching data
- โ Small to medium datasets
- โ Rapid prototyping
- โ Offline-first apps with simple data
Use SQLite when: #
- โ Complex data relationships
- โ Advanced queries with joins, aggregations
- โ Large datasets
- โ Data integrity requirements
- โ Reporting and analytics
- โ Existing SQL knowledge in team
๐ API Reference #
SecureDB (Main Interface) #
Quick Access Methods
setString(key, value)
/getString(key)
- String storagesetInt(key, value)
/getInt(key)
- Integer storagesetBool(key, value)
/getBool(key)
- Boolean storagesetMap(key, value)
/getMap(key)
- Map storageremove(key)
- Remove keyclearBox(boxName)
- Clear all data in boxcloseAll()
- Close all databases
Factory Methods
SecureDB.hive()
- Returns SecureHive instanceSecureDB.sqlite()
- Returns SecureSQLite instanceSecureDB.init(config)
- Initialize with configuration
SecureHive #
Access via SecureDB.hive()
or SecureHive.instance
:
openBox<T>(name, {encryptionKey})
- Open encrypted Hive boxcloseBox(name)
- Close specific boxdeleteBox(name)
- Delete box and encryption keyboxExists(name)
- Check if box existsgetOpenBoxNames()
- List open boxescloseAllBoxes()
- Close all open boxescompactAll()
- Compact all open boxesgetBoxSize(name)
- Get estimated box size
SecureBox #
Core Operations
get(key)
/put(key, value)
- Basic storagedelete(key)
/containsKey(key)
- Key managementclear()
/close()
- Box management
Batch Operations
putAll(Map<String, T>)
- Store multiple valuesgetAll(List<String>)
- Get multiple valuesdeleteAll(List<String>)
- Delete multiple keys
Advanced Features
watch({key})
- Listen to changestoMap()
- Convert to Mapwhere(predicate)
- Filter entriesupdate(key, updater)
- Update with function
SecureSQLite #
Access via SecureDB.sqlite()
or SecureSQLite.instance
:
openDatabase(name, {version, onCreate, onUpgrade, encryptionKey})
- Open databasecloseDatabase(name)
- Close specific databasedeleteDatabase(name)
- Delete database filedatabaseExists(name)
- Check if database existscloseAll()
- Close all databasesgetOpenDatabases()
- List open databasesvacuumAll()
- Vacuum all databasesoptimizeAll()
- Optimize all databasesenableWalMode()
- Enable WAL mode
SecureDatabase #
Core SQL Operations
execute(sql, [args])
- Execute SQL commandrawQuery(sql, [args])
- Raw SELECT queryinsert(table, values, {encryptedColumns})
- Insert with encryptionupdate(table, values, {where, encryptedColumns})
- Update with encryptionquery(table, {where, encryptedColumns})
- Query with decryptiondelete(table, {where})
- Delete records
Advanced Features
transaction(action)
- Execute in transactionbatch(operations)
- Batch operationscreateTable(name, columns, {encryptedColumns})
- Create table with encryptioninsertOrUpdate(table, values, {conflictColumns})
- UPSERT operation
๐ Security Features #
Encryption #
- Algorithm: AES-256-GCM for authenticated encryption
- Key Generation: Cryptographically secure random keys (256-bit)
- IV: Unique initialization vector for each encryption operation
- Key Storage: Platform-specific secure storage (iOS Keychain, Android Keystore)
Key Management #
- Automatic key generation per database/box
- Secure key storage using platform APIs
- Key rotation support (manual)
- Custom key support for advanced use cases
Data Protection #
- All sensitive data encrypted before storage
- No plaintext data written to disk
- Configurable column-level encryption for SQLite
- Automatic encryption/decryption transparent to developer
๐ Migration Guide #
From Hive #
// Before (regular Hive)
final box = await Hive.openBox('myBox');
await box.put('key', 'value');
String? value = box.get('key');
// After (SecureDB)
final box = await SecureDB.hive().openBox<String>('myBox');
// Or: final box = await SecureHive.instance.openBox<String>('myBox');
await box.put('key', 'value');
String? value = box.get('key');
// All other operations remain the same!
From SQLite #
// Before (regular sqflite)
final db = await openDatabase('mydb.db');
await db.insert('users', {'name': 'John'});
// After (SecureDB)
final db = await SecureDB.sqlite().openDatabase('mydb.db');
// Or: final db = await SecureSQLite.instance.openDatabase('mydb.db');
await db.insert('users', {'name': 'John'}, encryptedColumns: ['sensitive_field']);
// Most operations remain the same, just add encryptedColumns when needed!
โก Performance Tips #
- Batch Operations: Use
putAll
,getAll
, and batch operations for multiple items - Transactions: Wrap multiple SQLite operations in transactions
- Selective Encryption: Only encrypt sensitive columns in SQLite
- Connection Pooling: Reuse database connections
- Lazy Loading: Don't load all data at once, use pagination
- Proper Indexing: Create indexes on frequently queried columns
๐งช Testing #
// Test helper for encrypted data
import 'package:secure_db/secure_db.dart';
void main() {
group('SecureDB Tests', () {
setUpAll(() async {
await SecureDB.init();
});
test('should encrypt and decrypt data', () async {
final box = await SecureDB.hive().openBox<String>('test');
await box.put('test_key', 'sensitive_data');
final retrieved = box.get('test_key');
expect(retrieved, equals('sensitive_data'));
});
tearDownAll(() async {
await SecureDB.closeAll();
});
});
}
๐ค Contributing #
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
๐ License #
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Changelog #
1.0.4 #
- Improved API consistency with instance-based access pattern
- Enhanced singleton implementation for both Hive and SQLite
- Better support for both factory and direct instance access methods
- Updated documentation with comprehensive usage examples
1.0.1 #
- Fixed static analysis issues for improved code quality
- Removed debug print statements for cleaner production code
- Enhanced documentation with dual access method examples
1.0.0 #
- Initial release with Hive and SQLite support
- AES-256-GCM encryption for all data
- Platform-specific secure key storage
- Comprehensive API for both storage types
- Transaction and batch operation support
- Full documentation and examples