get_secure_storage_plus

A cryptography Secure version of GetStorage originally written by Jonny Borges (https://github.com/jonataslaw/get_storage).

GetSecureStorage is a secure, fast, extra light and synchronous key-value in memory, which backs up data to disk at each operation. It is written entirely in Dart and is based on the Cryptography dart package.

The cryptography library used is https://pub.dev/packages/cryptography

The algorithm used is 256-bit AES-GCM (Authenticated Encryption). Key derivation utilizes PBKDF2-SHA256. While the strict OWASP 2025 recommended standard is 600,000 iterations, the default iteration counts are dynamically adapted and minimized (10,000 to 30,000) for cross-platform apps to drastically reduce startup latency. If you require maximum security and don't mind a 2-4 second initialization delay, you can manually override this via GetSecureStorage.init(passwordIterations: 600000). Salt is embedded natively into the storage payload, removing the need for external salt files. Backwards Compatibility: Seamlessly reads and automatically migrates old version 1 databases into the new AES-GCM-256 format without losing user data!

Supports Android, iOS, Web, Mac, Linux, and Windows. Can store String, int, double, Map and List

Add to your pubspec:

dependencies:
  get_secure_storage_plus:

Install it

You can install packages from the command line:

with Flutter:

$  flutter packages get

Import it

Now in your Dart code, you can use:

import 'package:get_secure_storage_plus/get_secure_storage_plus.dart';

Initialize storage driver with await:

main() async {
  await GetSecureStorage.init(password: 'strongpassword');
  runApp(App());
}

use GetSecureStorage through an instance or use directly GetSecureStorage().read('key')

final box = GetSecureStorage(password: 'strongpassword');

To write information you must use write :

box.write('quote', 'GetSecureStorage is the best');

To read values you use read:

print(box.read('quote'));
// out: GetSecureStorage is the best

To remove a key, you can use remove:

box.remove('quote');

To listen changes you can use listen:

Function? disposeListen;
disposeListen = box.listen((){
  print('box changed');
});

If you subscribe to events, be sure to dispose them when using:

disposeListen?.call();

To listen changes on key you can use listenKey:

box.listenKey('key', (value){
  print('new key is $value');
});

To erase your container:

box.erase();

If you want to create different containers, simply give it a name. You can listen to specific containers, and also delete them.

GetSecureStorage g = GetSecureStorage(container:'MyStorage', password: 'strongpassword');

To initialize specific container:

await GetSecureStorage.init(container:'MyStorage', password: 'strongpassword');

SharedPreferences Implementation

class MyPref {
  static final _otherBox = () => GetSecureStorage(container:'MyPref', password: 'strongpassword');

  final username = ''.val('username');
  final age = 0.val('age');
  final price = 1000.val('price', getBox: _otherBox);

  // or
  final username2 = ReadWriteValue('username', '');
  final age2 = ReadWriteValue('age', 0);
  final price2 = ReadWriteValue('price', '', _otherBox);
}

...

void updateAge() {
  final age = 0.val('age');
  // or
  final age = ReadWriteValue('age', 0, () => box);
  // or
  final age = Get.find<MyPref>().age;

  age.val = 1; // will save to box
  final realAge = age.val; // will read from box
}

Best Practices & Performance Limitations

The Blob Problem GetSecureStorage works by loading the entire storage JSON dictionary into memory on init(), and synchronously applying reads/writes from memory. Then, in the background, it encrypts the entire dictionary mapping and flushes it to disk asynchronously.

Because of this, GetSecureStorage is optimized for a high volume of small keys (like settings, tokens, strings, layout configs).

Advice: You should never store massive blobs of data inside this package (such as 5MB Base64 encoded images, video bytes, or massive List<Map> caching structures). If you store a 5MB image in this storage, simply changing isDarkTheme = true will cause the entire 5MB JSON string to be re-encrypted and heavily slow down background disk operations. Keep your usage scoped to state and configurations!