Native Armor Vault
Secure native storage for Flutter secrets and API keys. Protects sensitive data using multi-layer encryption in C++ native code, preventing extraction through reverse engineering.
Why Native Armor Vault?
The Problem: API keys and secrets stored in Dart code can be extracted in minutes using decompilation tools.
The Solution: Native Armor Vault stores your secrets encrypted in compiled C++ native libraries, making extraction significantly harder.
Protection Against Common Attacks
| Attack Method | Without Protection | With Native Armor Vault |
|---|---|---|
| Dart decompilation | Secrets visible in 30 seconds | No secrets in Dart code |
strings command on binary |
N/A | Encrypted data only |
| Static analysis tools | N/A | Obfuscated function names |
| Hex editor inspection | N/A | No plaintext secrets |
| Debugger attachment | N/A | Optional detection |
| Rooted/Jailbroken devices | N/A | Optional detection |
Key Features
- Multi-layer encryption - XOR, S-box substitution, and bit rotation
- Compiler optimization protection - Prevents plaintext exposure during compilation
- Runtime key reconstruction - Encryption keys assembled at runtime
- Thread-safe - Safe for concurrent access
- Configurable security - Enable/disable checks for development vs production
- Cross-platform - Works on Android and iOS
- Zero runtime dependencies - Everything compiled into native code
Installation
Add to your pubspec.yaml:
dependencies:
native_armor_vault: ^2.0.3
Install:
flutter pub get
Quick Start
1. Create Configuration
Create native_vault.yaml in your project root:
xor_key: 'YOUR_UNIQUE_SECRET_KEY_2026'
# Security settings
security:
enable_checks: false # Set to true for production builds
violation_mode: 'fake'
secrets:
API_KEY: 'your-api-key-here'
DATABASE_URL: 'https://api.example.com'
STRIPE_KEY: 'sk_live_xxxxx'
Important: Add native_vault.yaml to .gitignore!
2. Generate Native Code
dart run native_armor_vault:generate
This creates encrypted C++ code for Android and iOS.
3. Use in Your App
import 'package:native_armor_vault/native_armor_vault.dart';
void main() {
// Access your secrets
final apiKey = ArmorVault.api_key;
final dbUrl = ArmorVault.database_url;
print('API Key: $apiKey');
}
4. Build Your App
# Clean build recommended after generation
flutter clean
flutter run
Configuration Options
Security Settings
security:
# Enable security checks (root, debugger, emulator detection)
enable_checks: false # false = development, true = production
# What to do when security violation detected
violation_mode: 'fake' # Options: 'throw', 'fake', 'empty'
Development mode (enable_checks: false):
- Works on emulators and simulators
- No security warnings
- Perfect for testing
Production mode (enable_checks: true):
- Detects rooted/jailbroken devices
- Detects debugger attachment
- Detects emulator environment
- Returns fake/empty data or throws exception on violation
Secret Naming
You can use any valid identifier names:
secrets:
# API Keys
OPENAI_KEY: 'sk-xxxxx'
STRIPE_PUBLISHABLE: 'pk_live_xxxxx'
# URLs
API_BASE_URL: 'https://api.myapp.com'
WEBSOCKET_URL: 'wss://ws.myapp.com'
# Tokens
AUTH_TOKEN: 'xxxxx'
REFRESH_TOKEN: 'xxxxx'
Access in Dart using lowercase names:
ArmorVault.openai_key
ArmorVault.stripe_publishable
ArmorVault.api_base_url
When Should You Use This?
Good Use Cases
- API keys and service credentials
- Backend endpoint URLs
- OAuth client secrets
- SDK initialization tokens
- Third-party service keys
Not Recommended For
- User passwords (use secure server authentication)
- Payment card data (never store on client)
- Highly sensitive personal data
- Data that should be server-side only
How It Works
- Generation Time: Your secrets are encrypted using multi-layer encryption and compiled into C++ native code
- Compile Time: C++ code is compiled into native libraries (.so for Android, static for iOS)
- Runtime: Secrets are decrypted on-demand using Flutter FFI
- Protection: Multiple techniques prevent extraction:
- Compiler optimization prevention
- Runtime key reconstruction
- Function name obfuscation
- Optional security checks
Best Practices
DO
- Always add
native_vault.yamlto.gitignore - Use different keys for development and production
- Regenerate after changing secrets:
dart run native_armor_vault:generate - Validate secrets server-side
- Rotate secrets regularly
- Run
flutter cleanafter regenerating
DON'T
- Commit
native_vault.yamlto version control - Store highly sensitive data (use backend instead)
- Rely solely on client-side protection
- Use weak encryption keys
- Skip server-side validation
Updating Secrets
When you need to change secrets:
# 1. Update native_vault.yaml
# 2. Regenerate
dart run native_armor_vault:generate
# 3. Clean and rebuild
flutter clean
flutter run
Platform Support
- Android: Minimum SDK 21 (Android 5.0)
- iOS: Minimum iOS 11.0
- Flutter: >=1.17.0
- Dart: ^3.10.7
Troubleshooting
"Failed to lookup symbol" error:
- Run
flutter clean - Regenerate:
dart run native_armor_vault:generate - For iOS: Run
cd ios && pod install
Secrets not updating:
- Always run
flutter cleanafter regeneration - Make sure you regenerated:
dart run native_armor_vault:generate
Works on emulator but not on real device:
- Check
enable_checkssetting innative_vault.yaml - Set to
falsefor development/testing
Example
See the example directory for a complete working example.
Comparison with Alternatives
| Solution | Security Level | Ease of Use | Works Offline |
|---|---|---|---|
| Plain Dart strings | Very Low | Very Easy | Yes |
| Environment variables | Low | Easy | Yes |
| flutter_secure_storage | Medium | Easy | Yes |
| Native Armor Vault | Medium-High | Easy | Yes |
| Backend-only secrets | Highest | Medium | No |
License
MIT License - see LICENSE file for details.
Contributing
Contributions are welcome! Please read our contributing guidelines before submitting pull requests.
Disclaimer
Important: While Native Armor Vault significantly increases the difficulty of extracting secrets from your app, no client-side security solution is completely unbreakable. Determined attackers with sufficient time and expertise may still be able to extract secrets from any client application.
This package is designed to raise the bar significantly - making casual reverse engineering impractical and requiring substantial effort and expertise to bypass. However, it should be part of a defense-in-depth strategy, not your only security measure.
Best practice: Always validate API keys and tokens on your backend, implement rate limiting, monitor for suspicious activity, and rotate secrets regularly. Client-side secret storage should complement, not replace, proper server-side security measures.
For maximum security of highly sensitive operations, consider keeping secrets server-side only and using secure authentication flows instead of storing secrets on the client.