Encrypt Env
A Dart CLI tool that generates obfuscated or encrypted Dart files from YAML or JSON configuration. It helps you protect API keys, secrets, tokens, and other sensitive data in Flutter and Dart applications.
Summary
- Installation
- Quick start
- Modes
- Setup
- Merging environments
- Key generation
- Test generation
- Customization
- Documentation
- Help
Installation
Activate globally via Dart:
dart pub global activate encrypt_env
Quick start
Run without arguments for an interactive experience:
encrypt_env gen
The CLI will guide you through each option:
? Choose a mode:
❯ XOR obfuscation (no dependencies)
AES-256 encryption (requires fortis)
? Choose a case style:
❯ camelCase
snake_case
SCREAMING_SNAKE_CASE
? Folder containing your config files: (environment)
? Config file name (without extension): (environment)
? Environment to merge (e.g. dev, prod — leave empty to skip):
? Output directory for generated Dart file: (lib)
? Output file name (without .dart): (environment)
? Generate test file? (Y/n)
Or pass flags directly for automation:
encrypt_env gen --style cc --env prod
When any flag is passed, the CLI uses default values for the remaining options without prompting.
Modes
XOR obfuscation
The default mode. Uses multi-layer XOR obfuscation with per-value salt, byte shuffling, and derived key passes. The generated file has zero external dependencies.
encrypt_env gen
Values are obfuscated — not visible as plain text in the source code or binary, but not cryptographically secure. Ideal for base URLs, SDK keys, and feature flags.
Flutter projects: For additional protection, enable Flutter's built-in obfuscation when building for release:
flutter build apk --obfuscate --split-debug-info=debug-info/
AES-256 encryption
Uses AES-256-GCM encryption via the fortis package. The generated file requires fortis as a dependency and a runtime key to decrypt.
# With your own key
encrypt_env gen --encrypt --key <base64_key>
# Auto-generate a key
encrypt_env gen --encrypt
When no key is provided, the CLI generates one and displays it in the console:
Generated a new AES-256 key:
hEvB+s5mpCLmmioI6Ji53JwIzx7ZQ5HUih/7CTv5S2I=
⚠ Save this key securely. You will need it at runtime.
The generated file includes an EncryptEnv class with an init() method that must be called before accessing any value:
import 'environment.dart';
void main() {
EncryptEnv.init('your-base64-key-here');
print(Environment.baseUrl);
}
Setup
Organize your project with a folder named environment and a config file (.yaml, .yml, or .json):
your_project/
├── environment/
│ └── environment.yaml # or .yml or .json
The CLI auto-detects the file format. Priority order:
.yaml>.yml>.json.You can change the folder and file name using
--folderand--configflags.
Basic example
Given the following environment/environment.yaml:
environment:
base_url: 'http://localhost:3000'
version: '1.0.0'
production: false
headers:
api-key: 'value'
endpoint:
endpoint_a: 'endpoint-a'
endpoint_b: 'endpoint-b'
Run:
encrypt_env gen
The file lib/environment.dart will be generated with sealed classes and strongly-typed getters:
sealed class Environment {
static String get baseUrl {
final List<int> encoded = [0xd5, 0x98, ...];
final List<int> salt = [...[0xaa, 0xbb, ...], ...[0xcc, 0xdd, ...]];
return _decode(encoded, salt);
}
static bool get production {
final List<int> encoded = [0xdb, 0x8d, ...];
final List<int> salt = [...[0x94, 0xb5, ...], ...[0xe3, 0xa0, ...]];
return bool.parse(_decode(encoded, salt));
}
static Map<String, dynamic> get headers {
return {
_decode([0xdc, ...], [...[...], ...[...]]): _apiKey,
};
}
}
sealed class Endpoint {
static String get endpointA { ... }
static String get endpointB { ... }
}
Each value has its own unique salt, split into two fragments for additional obscurity.
Merging environments
You can merge environment-specific overrides on top of a base config:
# environment/environment.yaml (base)
environment:
production: false
base_url: 'http://localhost:3000'
api_key: 'dev_key'
# environment/prod_environment.yaml (overrides)
environment:
production: true
base_url: 'https://api.example.com'
api_key: 'prod_key'
encrypt_env gen -e prod
Values from prod_environment.yaml override the base config. Unspecified values are preserved from the base.
Use any prefix:
staging,dev,uat, etc. Format:{prefix}_environment.yaml.
Key generation
Generate a random AES-256 key:
encrypt_env keygen
AES-256 key generated:
y67ImXMjCr1Uuo6jvF0pXBuomlshiwCgbwYQFRiUHbk=
Test generation
By default, a test file is generated alongside the Dart file at test/{out-file}_test.dart. The CLI automatically detects your project type by reading pubspec.yaml:
- Flutter project (has
flutterdependency) → usespackage:flutter_test/flutter_test.dart - Dart project → uses
package:test/test.dart - Package name → uses
package:name/...import style
Example generated test:
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/environment.dart';
void main() {
group('Environment', () {
test('baseUrl returns correct value', () {
expect(Environment.baseUrl, 'http://localhost:3000');
});
test('production returns correct value', () {
expect(Environment.production, false);
});
test('production returns bool', () {
expect(Environment.production, isA<bool>());
});
});
}
To disable test generation:
encrypt_env gen --no-test
⚠ In
--encryptmode, the generated test embeds the AES-256 key in plaintext. Do not commit it to a public repository — add the test file to.gitignoreor rotate the key before publishing.
Customization
Available flags
| Flag | Default | Description |
|---|---|---|
--folder |
environment |
Folder containing your configuration files |
--config |
environment |
Base config file name (without extension) |
-e, --env |
none | Environment name to merge (e.g., dev, prod) |
--out-dir |
lib |
Output directory for the generated Dart file |
--out-file |
environment |
Output Dart file name (without .dart) |
-s, --style |
cc |
Getter naming style: cc (camelCase), sc (snake_case), ssc (SCREAMING_SNAKE_CASE) |
--encrypt |
false |
Use AES-256-GCM encryption instead of XOR obfuscation |
-k, --key |
none | Base64 AES-256 key (used with --encrypt) |
--[no-]test |
true |
Generate a test file alongside the Dart file |
Documentation
Detailed documentation about how each mode works:
Help
To view all available commands and options:
encrypt_env -h
License
MIT License - see LICENSE for details.
Libraries
- encrypt_env
- Generate obfuscated or encrypted Dart files from YAML/JSON configuration.