Using Encrypted Shared Preferences in Flutter

Summary
Summary
Summary
Summary

This tutorial shows how to secure SharedPreferences in Flutter by keeping an AES key in flutter_secure_storage and encrypting values with the encrypt package before writing them to shared_preferences. It covers setup, key generation, encrypt/decrypt helpers, storage workflow, and best practices like using authenticated encryption and key rotation.

This tutorial shows how to secure SharedPreferences in Flutter by keeping an AES key in flutter_secure_storage and encrypting values with the encrypt package before writing them to shared_preferences. It covers setup, key generation, encrypt/decrypt helpers, storage workflow, and best practices like using authenticated encryption and key rotation.

This tutorial shows how to secure SharedPreferences in Flutter by keeping an AES key in flutter_secure_storage and encrypting values with the encrypt package before writing them to shared_preferences. It covers setup, key generation, encrypt/decrypt helpers, storage workflow, and best practices like using authenticated encryption and key rotation.

This tutorial shows how to secure SharedPreferences in Flutter by keeping an AES key in flutter_secure_storage and encrypting values with the encrypt package before writing them to shared_preferences. It covers setup, key generation, encrypt/decrypt helpers, storage workflow, and best practices like using authenticated encryption and key rotation.

Key insights:
Key insights:
Key insights:
Key insights:
  • Setup And Dependencies: Use shared_preferences for compatibility, flutter_secure_storage for key protection, and encrypt for AES operations.

  • Key Management: Generate a random AES key once, store it in secure storage (Keychain/Keystore), and never hard-code keys.

  • Read And Write Encrypted Values: Encrypt plaintext with a random IV, store iv+ciphertext in SharedPreferences, and decrypt on read.

  • Best Practices: Prefer AES-GCM for authenticated encryption, rotate keys, limit client-side sensitive data, and use platform access controls.

  • Implementation Pattern: Combining secure key storage with encrypted preference values balances compatibility and stronger confidentiality for mobile development.

Introduction

Mobile apps frequently need to persist small pieces of data: user preferences, tokens, feature flags. On Android and iOS the standard SharedPreferences (via the shared_preferences plugin) stores cleartext values on disk. For sensitive data you must encrypt values or use platform-provided secure storage. This tutorial shows a pragmatic pattern: keep an AES key in secure storage and encrypt values stored in SharedPreferences. This approach balances compatibility with existing code and stronger confidentiality for mobile development using Flutter.

Setup And Dependencies

Use three packages: shared_preferences for familiar key-value storage, flutter_secure_storage to hold cryptographic keys (backed by Keychain/Keystore), and encrypt to perform AES encryption.

Add to pubspec.yaml:

dependencies:
  shared_preferences: ^2.0.0
  flutter_secure_storage: ^8.0.0
  encrypt: ^5.0.0

Import them where you implement storage logic.

Key Management

Never hard-code AES keys in the app. Generate a random 256-bit key on first run and store it in flutter_secure_storage. The secure storage plugin uses platform-provided secure enclaves (Android Keystore / iOS Keychain). Keep the AES key secret and rotate it if you suspect compromise. Store the key as base64; retrieve and convert back to bytes when encrypting/decrypting.

Example helper to create or load a key (condensed):

final _secure = FlutterSecureStorage();
Future<Uint8List> _getAesKey() async {
  final existing = await _secure.read(key: 'aes_key');
  if (existing != null) return base64Decode(existing);
  final key = encrypt.Key.fromSecureRandom(32);
  await _secure.write(key: 'aes_key', value: base64Encode(key.bytes));
  return key.bytes;
}

Read And Write Encrypted Values

Strategy: Before writing to SharedPreferences, encrypt the plaintext with AES-CBC (or AES-GCM if you prefer authenticated encryption) using a random IV. Store the IV together with ciphertext (for example: base64(iv + ciphertext)). When reading, split IV and ciphertext, decrypt and return the plaintext. Use UTF-8 for string encoding.

Example encrypt/decrypt helpers:

Future<String> encryptValue(String plain) async {
  final keyBytes = await _getAesKey();
  final key = encrypt.Key(keyBytes);
  final iv = encrypt.IV.fromSecureRandom(16);
  final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc));
  final cipher = encrypter.encrypt(plain, iv: iv);
  return base64Encode(iv.bytes + cipher.bytes);
}

Future<String?> decryptValue(String stored) async {
  final raw = base64Decode(stored);
  final iv = encrypt.IV(Uint8List.fromList(raw.sublist(0, 16)));
  final cipherBytes = raw.sublist(16);
  final key = encrypt.Key(await _getAesKey());
  final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc));
  return encrypter.decrypt(encrypt.Encrypted(Uint8List.fromList(cipherBytes)), iv: iv);
}

With those helpers you can wrap SharedPreferences set/get operations:

  • To save: encrypted = await encryptValue(plain); await prefs.setString('secret_x', encrypted);

  • To read: encrypted = prefs.getString('secret_x'); if (encrypted!=null) plain = await decryptValue(encrypted);

This gives you the compatibility and convenience of SharedPreferences while ensuring stored values are opaque on disk.

Best Practices

  • Prefer authenticated encryption (AES-GCM) to detect tampering. The encrypt package supports AES-GCM; it returns combined ciphertext+tag. If you use CBC, include an HMAC to avoid undetected tampering.

  • Limit what you store client-side. Tokens with long-lived server privileges should be short-lived or refreshed via a secure backend.

  • Rotate keys: provide a migration path where you decrypt with the old key and re-encrypt with a new key after obtaining user consent or at login.

  • Protect key-access: on iOS use access control (biometric prompts) on the Keychain if the data requires user presence. flutter_secure_storage exposes some configuration for iOS and Android.

  • Test behavior across app uninstall/reinstall flows: secure storage may be cleared differently depending on OS and flags.

Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.

Conclusion

Encrypted Shared Preferences in Flutter is best implemented by combining secure key storage with deterministic encryption of values. Storing the AES key in flutter_secure_storage and ciphertext in shared_preferences keeps the developer workflow simple while adding cryptographic protection. Choose authenticated modes, rotate keys, and minimize what you store. This pattern is practical for many mobile development scenarios where compatibility with existing preferences API and improved confidentiality are both required.

Introduction

Mobile apps frequently need to persist small pieces of data: user preferences, tokens, feature flags. On Android and iOS the standard SharedPreferences (via the shared_preferences plugin) stores cleartext values on disk. For sensitive data you must encrypt values or use platform-provided secure storage. This tutorial shows a pragmatic pattern: keep an AES key in secure storage and encrypt values stored in SharedPreferences. This approach balances compatibility with existing code and stronger confidentiality for mobile development using Flutter.

Setup And Dependencies

Use three packages: shared_preferences for familiar key-value storage, flutter_secure_storage to hold cryptographic keys (backed by Keychain/Keystore), and encrypt to perform AES encryption.

Add to pubspec.yaml:

dependencies:
  shared_preferences: ^2.0.0
  flutter_secure_storage: ^8.0.0
  encrypt: ^5.0.0

Import them where you implement storage logic.

Key Management

Never hard-code AES keys in the app. Generate a random 256-bit key on first run and store it in flutter_secure_storage. The secure storage plugin uses platform-provided secure enclaves (Android Keystore / iOS Keychain). Keep the AES key secret and rotate it if you suspect compromise. Store the key as base64; retrieve and convert back to bytes when encrypting/decrypting.

Example helper to create or load a key (condensed):

final _secure = FlutterSecureStorage();
Future<Uint8List> _getAesKey() async {
  final existing = await _secure.read(key: 'aes_key');
  if (existing != null) return base64Decode(existing);
  final key = encrypt.Key.fromSecureRandom(32);
  await _secure.write(key: 'aes_key', value: base64Encode(key.bytes));
  return key.bytes;
}

Read And Write Encrypted Values

Strategy: Before writing to SharedPreferences, encrypt the plaintext with AES-CBC (or AES-GCM if you prefer authenticated encryption) using a random IV. Store the IV together with ciphertext (for example: base64(iv + ciphertext)). When reading, split IV and ciphertext, decrypt and return the plaintext. Use UTF-8 for string encoding.

Example encrypt/decrypt helpers:

Future<String> encryptValue(String plain) async {
  final keyBytes = await _getAesKey();
  final key = encrypt.Key(keyBytes);
  final iv = encrypt.IV.fromSecureRandom(16);
  final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc));
  final cipher = encrypter.encrypt(plain, iv: iv);
  return base64Encode(iv.bytes + cipher.bytes);
}

Future<String?> decryptValue(String stored) async {
  final raw = base64Decode(stored);
  final iv = encrypt.IV(Uint8List.fromList(raw.sublist(0, 16)));
  final cipherBytes = raw.sublist(16);
  final key = encrypt.Key(await _getAesKey());
  final encrypter = encrypt.Encrypter(encrypt.AES(key, mode: encrypt.AESMode.cbc));
  return encrypter.decrypt(encrypt.Encrypted(Uint8List.fromList(cipherBytes)), iv: iv);
}

With those helpers you can wrap SharedPreferences set/get operations:

  • To save: encrypted = await encryptValue(plain); await prefs.setString('secret_x', encrypted);

  • To read: encrypted = prefs.getString('secret_x'); if (encrypted!=null) plain = await decryptValue(encrypted);

This gives you the compatibility and convenience of SharedPreferences while ensuring stored values are opaque on disk.

Best Practices

  • Prefer authenticated encryption (AES-GCM) to detect tampering. The encrypt package supports AES-GCM; it returns combined ciphertext+tag. If you use CBC, include an HMAC to avoid undetected tampering.

  • Limit what you store client-side. Tokens with long-lived server privileges should be short-lived or refreshed via a secure backend.

  • Rotate keys: provide a migration path where you decrypt with the old key and re-encrypt with a new key after obtaining user consent or at login.

  • Protect key-access: on iOS use access control (biometric prompts) on the Keychain if the data requires user presence. flutter_secure_storage exposes some configuration for iOS and Android.

  • Test behavior across app uninstall/reinstall flows: secure storage may be cleared differently depending on OS and flags.

Vibe Studio

Vibe Studio, powered by Steve’s advanced AI agents, is a revolutionary no-code, conversational platform that empowers users to quickly and efficiently create full-stack Flutter applications integrated seamlessly with Firebase backend services. Ideal for solo founders, startups, and agile engineering teams, Vibe Studio allows users to visually manage and deploy Flutter apps, greatly accelerating the development process. The intuitive conversational interface simplifies complex development tasks, making app creation accessible even for non-coders.

Conclusion

Encrypted Shared Preferences in Flutter is best implemented by combining secure key storage with deterministic encryption of values. Storing the AES key in flutter_secure_storage and ciphertext in shared_preferences keeps the developer workflow simple while adding cryptographic protection. Choose authenticated modes, rotate keys, and minimize what you store. This pattern is practical for many mobile development scenarios where compatibility with existing preferences API and improved confidentiality are both required.

Build Flutter Apps Faster with Vibe Studio

Build Flutter Apps Faster with Vibe Studio

Build Flutter Apps Faster with Vibe Studio

Build Flutter Apps Faster with Vibe Studio

Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.

Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.

Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.

Vibe Studio is your AI-powered Flutter development companion. Skip boilerplate, build in real-time, and deploy without hassle. Start creating apps at lightning speed with zero setup.

Other Insights

Other Insights

Other Insights

Other Insights

Join a growing community of builders today

Join a growing community of builders today

Join a growing community of builders today

Join a growing community of builders today

Join a growing community of builders today

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025

28-07 Jackson Ave

Walturn

New York NY 11101 United States

© Steve • All Rights Reserved 2025