native_armor_vault 1.0.0
native_armor_vault: ^1.0.0 copied to clipboard
Native code obfuscation for Flutter. Encrypts secrets using rotating XOR and stores them in C++ native layer for better protection against reverse engineering.
Native Armor Vault 🔐 #
A Flutter plugin that provides native code obfuscation for sensitive data. Secrets are encrypted using rotating XOR and stored in the C++ native layer (.so for Android, statically linked for iOS), making them harder to extract through reverse engineering compared to plain Dart code.
🎯 Why Native Armor Vault? #
Problem: Storing API keys, tokens, and secrets directly in Dart code makes them easily extractable through decompilation.
Solution: Native Armor Vault obfuscates your secrets by encrypting them with rotating XOR and embedding them in compiled native C++ libraries.
⚠️ Security Level - Be Realistic! #
This is OBFUSCATION, not military-grade encryption!
| Threat Level | Protection | Recommendation |
|---|---|---|
| Script kiddies | ✅ Protected | Safe to use |
| Casual reverse engineers | ⚠️ Slows them down | Use with caution |
| Experienced attackers | ❌ Can be broken | DO NOT rely on this alone |
✅ Good Use Cases #
- Public API keys (with rate limiting on backend)
- Non-critical configuration
- Hobby/indie projects
- Adding extra layer on top of backend validation
❌ DO NOT Use For #
- Payment credentials
- User passwords or PII
- Cryptographic keys
- Anything requiring real security
Always validate on backend! This is defense-in-depth, not a security solution.
✨ Features #
- 🔒 Native C++ Storage: Secrets compiled into native libraries
- 🔐 Rotating XOR: Uses all characters of encryption key (v1.0.0+)
- 🚀 Automated Code Generation: CLI tool generates C++ and Dart code
- 📱 Cross-Platform: Android (
.so) and iOS (static linking) - ⚡ Zero Runtime Overhead: Secrets decrypted on-demand via FFI
- 🛡️ Obfuscation: Harder to extract than plain Dart code
- 🎨 Flexible Naming: Use any custom secret names you want
- 🔧 No Memory Leaks: Uses static buffers (v1.0.0+)
🔍 Known Limitations #
Be aware of these technical limitations:
-
XOR key is visible in binary
- The encryption key is embedded as a byte array in compiled code
- Can be extracted with hex editors or reverse engineering tools
- This is intentional - we prioritize simplicity over complexity
-
Not cryptographically secure
- XOR is obfuscation, not encryption
- Experienced reverse engineers can break this
- Always validate secrets on your backend!
-
Static secrets only
- Secrets are compiled into the binary
- Cannot be changed without rebuilding the app
- Not suitable for user-specific or dynamic data
Remember: This is defense-in-depth, not a standalone security solution!
📦 Installation #
Add to your pubspec.yaml:
dependencies:
native_armor_vault: ^0.0.9
Then run:
flutter pub get
🚀 Quick Start #
1. Create Configuration File #
In your project root (same level as pubspec.yaml), create native_vault.yaml:
xor_key: 'YOUR_UNIQUE_SECRET_KEY_2026'
secrets:
API_KEY: 'sk-1234567890abcdef'
DATABASE_URL: 'https://api.example.com/db'
SECRET_TOKEN: 'my-super-secret-token'
💡 Custom Names: You can use ANY names! Each key automatically generates:
- C++ function:
get_<KEY_NAME>()- Dart getter:
ArmorVault.<key_name_lowercase>Example:
MY_CUSTOM_SECRET: 'value'→ArmorVault.my_custom_secret
⚠️ CRITICAL: Add
native_vault.yamlto.gitignoreimmediately!
2. Update .gitignore #
Add these lines to your .gitignore:
# Native Armor Vault - DO NOT COMMIT SECRETS!
native_vault.yaml
android/src/main/cpp/native_vault.cpp
ios/Classes/native_vault.cpp
lib/armor_vault.g.dart
3. Generate Native Code #
Run the generator in your project root:
dart run native_armor_vault:generate
This creates:
- ✅
android/src/main/cpp/native_vault.cpp- Android native code - ✅
ios/Classes/native_vault.cpp- iOS native code - ✅
.dart_tool/native_armor_vault/ios/Classes/native_vault.cpp- iOS build cache - ✅
lib/armor_vault.g.dart- Dart FFI bridge
🍎 iOS Users - IMPORTANT!
After runninggenerate, you MUST run:cd ios && pod install && cd ..This copies the C++ files to the plugin directory. Skipping this step will cause "symbol not found" errors!
4. iOS: Install Pods #
Required for iOS only:
cd ios
pod install
cd ..
You should see:
✅ Copied native_vault.cpp from .dart_tool
If you see a warning instead, run dart run native_armor_vault:generate first!
5. 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;
final token = ArmorVault.secret_token;
print('API Key: $apiKey');
}
🔧 How It Works #
Architecture Overview #
┌─────────────────────┐
│ native_vault.yaml │ 1. Define secrets
└──────────┬──────────┘
│
▼
┌─────────────────────┐
│ CLI Generator │ 2. XOR encrypt & generate code
└──────────┬──────────┘
│
├─────────────────┬─────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ C++ Code │ │ C++ Code │ │ Dart FFI │
│ (Android)│ │ (iOS) │ │ Bridge │
└────┬─────┘ └────┬─────┘ └────┬─────┘
│ │ │
▼ ▼ │
┌──────────┐ ┌──────────┐ │
│ .so │ │ Static │ │
│ Library │ │ Link │ │
└────┬─────┘ └────┬─────┘ │
│ │ │
└────────┬────────┘ │
▼ ▼
┌─────────────────────────────────┐
│ Flutter App (FFI) │ 3. Runtime access
└─────────────────────────────────┘
Platform-Specific Details #
Android
- Build Time: CMake compiles
native_vault.cpp→libnative_armor_vault.so - Runtime:
DynamicLibrary.open('libnative_armor_vault.so')loads the library - Location: Bundled in APK under
lib/<architecture>/
iOS
- Build Time: C++ code compiled and statically linked into the app binary
- Runtime:
DynamicLibrary.process()accesses symbols from the main executable - Location: Embedded directly in the app binary (no separate
.dylib)
📖 Why
DynamicLibrary.process()on iOS?On iOS, the C++ code is statically linked into the main app executable during compilation.
DynamicLibrary.process()returns a handle to the current process, allowing FFI to look up symbols (likeget_API_KEY) that are already loaded in memory as part of the app binary.
Security Flow #
native_vault.yaml → XOR Encryption → C++ Code → Native Binary → FFI → Dart
(gitignored) (build time) (compiled) (.so/binary) (runtime)
📚 Complete Usage Guide #
Custom Secret Names #
You have complete freedom in naming your secrets:
xor_key: 'MY_SUPER_SECRET_KEY'
secrets:
# API Keys
OPENAI_API_KEY: 'sk-proj-xxxxx' # → ArmorVault.openai_api_key
STRIPE_PUBLISHABLE: 'pk_live_xxxxx' # → ArmorVault.stripe_publishable
# URLs & Endpoints
API_BASE_URL: 'https://api.myapp.com' # → ArmorVault.api_base_url
WEBSOCKET_URL: 'wss://ws.myapp.com' # → ArmorVault.websocket_url
# Configuration
FIREBASE_CONFIG: '{"apiKey":"xxx"}' # → ArmorVault.firebase_config
SENTRY_DSN: 'https://xxx@sentry.io/xxx' # → ArmorVault.sentry_dsn
# Custom Names - Anything you want!
MY_CUSTOM_SECRET: 'any-value-here' # → ArmorVault.my_custom_secret
PAYMENT_WEBHOOK: 'https://webhook.com' # → ArmorVault.payment_webhook
Naming Rules:
- ✅ Use UPPERCASE (recommended):
API_KEY - ✅ Underscores allowed:
MY_SECRET_TOKEN - ✅ Numbers allowed:
SECRET_V2 - ❌ No spaces
- ❌ No special characters (-, ., etc.)
Real-World Example #
import 'package:flutter/material.dart';
import 'package:native_armor_vault/native_armor_vault.dart';
import 'package:http/http.dart' as http;
class ApiService {
static final String _apiKey = ArmorVault.openai_api_key;
static final String _baseUrl = ArmorVault.api_base_url;
Future<String> fetchData() async {
final response = await http.get(
Uri.parse('$_baseUrl/endpoint'),
headers: {
'Authorization': 'Bearer $_apiKey',
'Content-Type': 'application/json',
},
);
if (response.statusCode == 200) {
return response.body;
} else {
throw Exception('Failed to load data');
}
}
}
void main() {
runApp(MyApp());
// Verify secrets loaded correctly (development only)
debugPrint('API Key loaded: ${ArmorVault.openai_api_key.substring(0, 10)}...');
}
Updating Secrets #
When you modify native_vault.yaml:
# 1. Regenerate code
dart run native_armor_vault:generate
# 2. Clean build
flutter clean
# 3. Rebuild app
flutter run
🔐 Security Best Practices #
✅ DO #
- Always gitignore
native_vault.yamland generated files - Use different keys for development and production
- Rotate secrets regularly
- Combine with backend validation - verify API keys server-side
- Use for: API keys, service URLs, OAuth secrets, SDK tokens
- Generate strong XOR keys - use random, long strings
❌ DON'T #
- Don't commit
native_vault.yamlto version control - Don't use for user passwords or payment card data
- Don't rely solely on this - combine with other security measures
- Don't use weak XOR keys - avoid simple strings like "password"
- Don't store highly sensitive data that should be backend-only
🔍 Troubleshooting #
"native_vault.yaml not found" #
Problem: Generator can't find the configuration file.
Solution: Ensure native_vault.yaml is in your project root (same directory as pubspec.yaml).
your_project/
├── pubspec.yaml
├── native_vault.yaml ← Must be here
└── lib/
"Library not found" on Android #
Problem: Native library not built or not found at runtime.
Solution:
cd android
./gradlew clean
cd ..
flutter clean
flutter pub get
dart run native_armor_vault:generate
flutter run
"Symbol not found" on iOS #
Problem: Native symbols not linked properly.
Solution:
cd ios
rm -rf Pods Podfile.lock
pod install
cd ..
dart run native_armor_vault:generate
flutter clean
flutter run
Secrets not updating after changing native_vault.yaml #
Problem: Old generated code still being used.
Solution:
# Always regenerate and clean after changes
dart run native_armor_vault:generate
flutter clean
flutter run