Native Armor Vault

pub package License: MIT

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
  • 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

  1. Generation Time: Your secrets are encrypted using multi-layer encryption and compiled into C++ native code
  2. Compile Time: C++ code is compiled into native libraries (.so for Android, static for iOS)
  3. Runtime: Secrets are decrypted on-demand using Flutter FFI
  4. Protection: Multiple techniques prevent extraction:
    • Compiler optimization prevention
    • Runtime key reconstruction
    • Function name obfuscation
    • Optional security checks

Best Practices

DO

  • Always add native_vault.yaml to .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 clean after regenerating

DON'T

  • Commit native_vault.yaml to 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 clean after regeneration
  • Make sure you regenerated: dart run native_armor_vault:generate

Works on emulator but not on real device:

  • Check enable_checks setting in native_vault.yaml
  • Set to false for 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.