A simple and secure storage system for Flutter. Supports Android, iOS, macOS, Windows and web !
I'm currently creating a TOTP app where secrets are encrypted using a master password and I need a secure place to store the encryption / decryption key.
I knew that Flutter already had a such package called flutter_secure_storage
. The only problem
is that it have 100+ open issues on Github, and that the author is currently inactive on
Github.
That's why I've decided to create my own solution : Simple Secure Storage (SSS).
- Very very simple and straightforward.
- Supports Android, iOS, macOS, Windows, Linux and web.
- Allows data to be cached (so that you can access it as fast as possible).
- Secure.
- Again, very simple.
Simple Secure Storage uses :
- Keychain on Apple devices, which is supported since iOS 2.0 and macOS 10.6.
EncryptedSharedPreferences
on Android, which supports a minimum SDK version of, at least, 21.wincred.h
on Windows, which seems to be available since Windows XP.libsecret
on Linux. Therefore, you need a secret service (gnome_keyring
is commonly installed).sembast_web
andwebcrypto
on web.
Run the following command to add Simple Secure Storage to your Flutter project :
flutter pub add simple_secure_storage
Then, please make sure you follow the specific instructions for each platform you're targeting.
Update the minimum SDK version in your android/app/build.gradle
:
android {
<!-- Other settings -->
defaultConfig {
minSdkVersion 18
<!-- More settings -->
}
<!-- And more settings -->
}
Also, as stated on Android Developers,
WARNING: The preference file should not be backed up with Auto Backup. When restoring the file it is likely the key used to encrypt it will no longer be present. You should exclude all
EncryptedSharedPreferences
from backup using backup rules.
so either you completely disable auto backup, in your AndroidManifest.xml
:
<application
<!-- Some settings -->
android:allowBackup="false"
android:fullBackupContent="false">
or you only disable the backup of the encrypted shared preferences, which can be done
using backup rules.
Note that the sharedpref
path is the namespace
key you're passing to the initialize
method
of the plugin.
In Xcode, go to Project settings > Capabilities and enable Keychain Sharing (see this).
Run the following command to install libsecret-1-dev
:
sudo apt install -y libsecret-1-dev
Here's a simple example to get started.
// Initialize the plugin before using. Typically done in your `main()` method.
// Please don't forget to provide your namespace and your app name.
if (kIsWeb) {
// To secure your data on Flutter web, we have to encrypt it using a password and a salt.
await SimpleSecureStorage.initialize(WebInitializationOptions(keyPassword: 'password', encryptionSalt: 'salt'));
} else {
await SimpleSecureStorage.initialize(); // Feel free to use `InitializationOptions` if you want here too.
}
// Write a value.
await SimpleSecureStorage.write('key', 'value');
// Check if a value exists.
print(await SimpleSecureStorage.has('key')); // Will print "true".
// Read a value.
print(await SimpleSecureStorage.read('key')); // Will print "value".
// Remove a value.
await SimpleSecureStorage.delete('key');
// Clear everything.
await SimpleSecureStorage.clear();
In the previous snippet, everything is being read "on demand". You may want to access your data
without always having to write await
. To do so, use the class CachedSimpleSecureStorage
.
It behaves exactly like the snippet above, except that you don't have to call await SimpleSecureStorage.initialize()
,
but await CachedSimpleSecureStorage.getInstance()
.
If you want a more complete example, feel free to check and run this one, which available on Github. Note that, to run the example app on Darwin platforms (iOS & macOS), you need to configure the development team in the project settings.
You have a lot of options to contribute to this project ! You can :