native_secured_storage 1.0.0 copy "native_secured_storage: ^1.0.0" to clipboard
native_secured_storage: ^1.0.0 copied to clipboard

A Flutter plugin for securely storing primitive data types using Android Keystore and iOS Keychain.

Native Secured Storage #

native_secured_storage is a Flutter plugin designed for securely storing and retrieving primitive data types (int, double, bool, and String) using Android Keystore and iOS Keychain. This ensures data is encrypted at rest and protected against unauthorized access, even if the device is compromised.


Why Use native_secured_storage? #

Security Features #

  1. Android Keystore with EncryptedSharedPreferences:

    • Uses AES256 encryption with a unique key stored securely in the Android Keystore.
    • Ensures encryption and decryption happen only within the device.
  2. iOS Keychain:

    • Integrates directly with Apple's Keychain, providing system-level security for sensitive data.
    • Protects data using the device’s secure enclave, if available.
  3. No Plaintext Storage:

    • All data is encrypted before being saved, ensuring that sensitive information is never stored in plaintext.
  4. Platform Isolation:

    • Separate implementations for Android and iOS ensure data is stored securely in each platform's native environment.

Use Cases #

  • Authentication: Securely store tokens, passwords, or sensitive user credentials.
  • Preferences: Save encrypted app preferences such as user settings or feature flags.
  • Secure Identifiers: Store unique identifiers or keys for app logic.

Features #

  • Cross-platform: Supports both Android and iOS.
  • Type Support: Securely handles int, double, bool, and String types.
  • Easy-to-use API: Simplified Dart API for saving, retrieving, and deleting data.
  • Error Handling: Comprehensive error handling to catch issues during encryption or storage operations.

Installation #

Add native_secured_storage to your pubspec.yaml:

dependencies:
  native_secured_storage: ^1.0.0

Run the following command to install the package:

flutter pub get

Usage #

Import the Package #

import 'package:native_secured_storage/native_secured_storage.dart';

Save a Value #

await NativeSecuredStorage.save('key_name', 123); // Save an integer
await NativeSecuredStorage.save('key_name', 45.67); // Save a double
await NativeSecuredStorage.save('key_name', true); // Save a boolean
await NativeSecuredStorage.save('key_name', 'Hello World'); // Save a string

Retrieve a Value #

final value = await NativeSecuredStorage.retrieve('key_name');
if (value != null) {
  print('Retrieved value: $value');
} else {
  print('No value found for the given key.');
}

Delete a Value #

await NativeSecuredStorage.delete('key_name');
print('Value deleted successfully.');

Example #

Below is a complete example using native_secured_storage:

import 'package:flutter/material.dart';
import 'package:native_secured_storage/native_secured_storage.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Native Secured Storage Example',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: SecureStorageDemo(),
    );
  }
}

class SecureStorageDemo extends StatefulWidget {
  @override
  _SecureStorageDemoState createState() => _SecureStorageDemoState();
}

class _SecureStorageDemoState extends State<SecureStorageDemo> {
  final TextEditingController _keyController = TextEditingController();
  final TextEditingController _valueController = TextEditingController();
  String? _retrievedValue;

  Future<void> _saveValue() async {
    final key = _keyController.text;
    final value = _valueController.text;

    if (key.isEmpty || value.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Key and value cannot be empty')),
      );
      return;
    }

    dynamic parsedValue;
    if (value.toLowerCase() == 'true' || value.toLowerCase() == 'false') {
      parsedValue = value.toLowerCase() == 'true';
    } else if (double.tryParse(value) != null) {
      parsedValue = value.contains('.') ? double.parse(value) : int.parse(value);
    } else {
      parsedValue = value;
    }

    try {
      await NativeSecuredStorage.save(key, parsedValue);
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Value saved successfully')),
      );
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error saving value: $e')),
      );
    }
  }

  Future<void> _retrieveValue() async {
    final key = _keyController.text;

    if (key.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Key cannot be empty')),
      );
      return;
    }

    try {
      final value = await NativeSecuredStorage.retrieve(key);
      setState(() {
        _retrievedValue = value?.toString();
      });
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Value retrieved successfully')),
      );
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error retrieving value: $e')),
      );
    }
  }

  Future<void> _deleteValue() async {
    final key = _keyController.text;

    if (key.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Key cannot be empty')),
      );
      return;
    }

    try {
      await NativeSecuredStorage.delete(key);
      setState(() {
        _retrievedValue = null;
      });
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Value deleted successfully')),
      );
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error deleting value: $e')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Secure Storage Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            TextField(
              controller: _keyController,
              decoration: InputDecoration(labelText: 'Key'),
            ),
            TextField(
              controller: _valueController,
              decoration: InputDecoration(labelText: 'Value'),
            ),
            SizedBox(height: 16),
            Row(
              children: [
                ElevatedButton(
                  onPressed: _saveValue,
                  child: Text('Save'),
                ),
                SizedBox(width: 8),
                ElevatedButton(
                  onPressed: _retrieveValue,
                  child: Text('Retrieve'),
                ),
                SizedBox(width: 8),
                ElevatedButton(
                  onPressed: _deleteValue,
                  child: Text('Delete'),
                ),
              ],
            ),
            SizedBox(height: 16),
            if (_retrievedValue != null)
              Text('Retrieved Value: $_retrievedValue'),
          ],
        ),
      ),
    );
  }
}

Testing #

Run the example app and perform the following actions:

  1. Save values of different types (int, double, bool, String).
  2. Retrieve and verify the values.
  3. Delete a value and confirm it’s removed.

License #

This plugin is released under the MIT License.

2
likes
140
points
2
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin for securely storing primitive data types using Android Keystore and iOS Keychain.

Homepage

Documentation

API reference

License

unknown (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on native_secured_storage

Packages that implement native_secured_storage