m_security 0.3.0
m_security: ^0.3.0 copied to clipboard
A high-performance cryptographic SDK for Flutter powered by native Rust via FFI. Provides authenticated encryption (AES-256-GCM, ChaCha20-Poly1305), modern hashing (BLAKE3, SHA-3, Argon2id), key deriv [...]
M-Security #
A native Rust security SDK for Flutter, providing high-performance cryptographic services, streaming encryption with compression, an encrypted virtual file system (EVFS), and secure memory management. All operations run in Rust through Flutter Rust Bridge. No Dart-level crypto, no platform channels.
Built and maintained by the Dev Department of MicroClub, the computer science club at USTHB (University of Science and Technology Houari Boumediene, Algiers).
Features #
| Category | Algorithm / Feature | Highlights |
|---|---|---|
| AEAD Encryption | AES-256-GCM | Industry-standard, hardware-accelerated on most CPUs |
| ChaCha20-Poly1305 | Optimized for mobile (no AES hardware needed) | |
| Streaming Encryption | AES-256-GCM / ChaCha20 | Chunk-based processing with progress callbacks |
| Compression | Zstd, Brotli | Configurable levels, integrated into streaming and EVFS |
| Hashing | BLAKE3 | Ultra-fast, one-shot and streaming |
| SHA-3-256 (Keccak) | NIST-standard, one-shot and streaming | |
| Password Hashing | Argon2id | PHC winner, Mobile and Desktop presets |
| Key Derivation | HKDF-SHA256 | RFC 5869, extract-then-expand with domain separation |
| Encrypted VFS (EVFS) | .vault container |
Named segments, WAL recovery, shadow index, secure deletion |
Security by design:
- All key material lives in Rust behind opaque handles; raw keys never cross FFI
- Automatic memory zeroization on drop (
ZeroizeOnDrop) - Nonces generated internally via OS-level CSPRNG (
OsRng) - AEAD tag verification prevents silent decryption of tampered data
panic = "abort"in release profile, preventing undefined behavior from panics crossing FFIclippy::unwrap_used = "deny", ensuring all operations returnResult<T, CryptoError>
Installation #
Add to your pubspec.yaml:
dependencies:
m_security: ^0.3.0
Then run:
flutter pub get
Prerequisites #
M-Security compiles Rust code during the Flutter build. You need:
-
Rust toolchain (stable):
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -
Platform-specific tools:
Platform Requirements Android Android NDK (r27c recommended) iOS / macOS Xcode with command line tools Linux clang,cmake,ninja-build,pkg-config,libgtk-3-devWindows Visual Studio Build Tools + LLVM
Rust compilation is handled automatically by Cargokit during flutter build / flutter run.
Getting Started #
Initialize the Rust library once at app startup:
import 'package:m_security/m_security.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await RustLib.init();
runApp(const MyApp());
}
Usage #
All examples below use a single import:
import 'package:m_security/m_security.dart';
AES-256-GCM Encryption #
final aes = AesGcmService();
await aes.initWithRandomKey();
// Encrypt and decrypt raw bytes
final encrypted = await aes.encrypt(plaintext);
final decrypted = await aes.decrypt(encrypted);
// Convenience: encrypt and decrypt UTF-8 strings
final ciphertext = await aes.encryptString('sensitive data');
final original = await aes.decryptString(ciphertext);
ChaCha20-Poly1305 Encryption #
final chacha = Chacha20Service();
await chacha.initWithRandomKey();
// Basic encrypt and decrypt
final encrypted = await chacha.encryptString('sensitive data');
final original = await chacha.decryptString(encrypted);
// With Associated Authenticated Data (AAD)
final ct = await chacha.encryptString('payload', aad: 'metadata');
final pt = await chacha.decryptString(ct, aad: 'metadata');
Both ciphers output nonce || ciphertext || tag. Nonces (12 bytes) are auto-generated and authentication tags (16 bytes) are appended automatically.
Argon2id Password Hashing #
// Hash a password (returns PHC-format string)
final hash = await argon2IdHash(password: 'hunter2');
// Verify a password against a hash
await argon2IdVerify(phcHash: hash, password: 'hunter2');
// Explicit preset selection
final hash = await argon2IdHash(
password: 'hunter2',
preset: Argon2Preset.desktop, // 256 MiB, t=4, p=8
);
The default preset is selected at compile time: Argon2Preset.mobile (64 MiB, t=3, p=4) unless built with -DIS_DESKTOP=true.
HKDF-SHA256 Key Derivation #
// Derive a key from input key material
final key = MHKDF.derive(
ikm: masterKeyBytes,
salt: saltBytes, // optional
info: Uint8List.fromList('encryption-key'.codeUnits),
outputLen: 32,
);
// Domain separation: same master key, different derived keys
final encKey = MHKDF.derive(ikm: master, info: utf8.encode('enc'), outputLen: 32);
final macKey = MHKDF.derive(ikm: master, info: utf8.encode('mac'), outputLen: 32);
// Two-phase: extract PRK, then expand
final prk = MHKDF.extract(ikm: masterKeyBytes, salt: saltBytes);
final derived = await MHKDF.expand(prk: prk, info: infoBytes, outputLen: 32);
Output length must be between 1 and 8160 bytes (RFC 5869 limit for SHA-256: 255 * 32).
Streaming Encryption #
import 'package:m_security/src/rust/api/streaming.dart';
// Encrypt a file in chunks with progress
final encrypted = await streamEncrypt(
plaintext: largeData,
algorithm: StreamAlgorithm.aes256Gcm,
compression: CompressionAlgorithm.zstd,
compressionLevel: 3,
onProgress: (progress) => print('${(progress * 100).toInt()}%'),
);
// Decrypt
final decrypted = await streamDecrypt(
ciphertext: encrypted,
algorithm: StreamAlgorithm.aes256Gcm,
compression: CompressionAlgorithm.zstd,
);
Encrypted Virtual File System (EVFS) #
import 'package:m_security/m_security.dart';
// Create a vault
final vault = VaultService();
await vault.create(path: '/path/to/my.vault', sizeBytes: 10 * 1024 * 1024);
// Write a segment (with optional compression)
await vault.writeSegment(
name: 'secret.txt',
data: utf8.encode('confidential'),
compression: CompressionAlgorithm.zstd,
);
// Read it back
final data = await vault.readSegment(name: 'secret.txt');
// List segments, delete, close
final segments = await vault.listSegments();
await vault.deleteSegment(name: 'secret.txt');
await vault.close();
BLAKE3 & SHA-3-256 Hashing #
For one-shot and streaming hashing, use the lower-level FFI API directly:
import 'package:m_security/src/rust/api/hashing.dart';
// One-shot hashing (32-byte output)
final blake3Digest = await blake3Hash(data: inputBytes);
final sha3Digest = await sha3Hash(data: inputBytes);
// Streaming: process data in chunks
final hasher = createBlake3(); // or createSha3()
await hasherUpdate(handle: hasher, data: chunk1);
await hasherUpdate(handle: hasher, data: chunk2);
final digest = await hasherFinalize(handle: hasher);
// Reset and reuse
await hasherReset(handle: hasher);
Architecture #
Key design decisions:
- Opaque handles.
CipherHandleandHasherHandleare#[frb(opaque)]. Dart holds a pointer, never raw key bytes. - Trait objects.
Box<dyn Encryption>andBox<dyn Hasher>withSend + Sync + 'staticenable runtime algorithm selection. - SecretBuffer. All key material is wrapped in
SecretBufferwhich derivesZeroizeOnDrop. Memory is zeroed when handles are dropped. - No panics across FFI.
panic = "abort"in release profile. All FFI functions returnResult<T, CryptoError>. - Format headers. Encrypted data includes a
MSECmagic header with version and algorithm identifiers for forward compatibility.
Rust API Reference #
Encryption (CipherHandle) #
create_aes256_gcm(key: Vec<u8>) -> Result<CipherHandle>
create_chacha20_poly1305(key: Vec<u8>) -> Result<CipherHandle>
encrypt(cipher, plaintext, aad) -> Result<Vec<u8>>
decrypt(cipher, ciphertext, aad) -> Result<Vec<u8>>
generate_aes256_gcm_key() -> Result<Vec<u8>>
generate_chacha20_poly1305_key() -> Result<Vec<u8>>
encryption_algorithm_id(cipher) -> String
Hashing (HasherHandle) #
blake3_hash(data) -> Vec<u8> (one-shot, 32 bytes)
sha3_hash(data) -> Vec<u8> (one-shot, 32 bytes)
create_blake3() -> HasherHandle (streaming)
create_sha3() -> HasherHandle (streaming)
hasher_update(handle, data) -> Result<()>
hasher_reset(handle) -> Result<()>
hasher_finalize(handle) -> Result<Vec<u8>>
hasher_algorithm_id(handle) -> Result<String>
Password Hashing (Argon2id) #
argon2id_hash(password, preset) -> Result<String> (PHC)
argon2id_hash_with_salt(password, salt, preset) -> Result<String> (PHC)
argon2id_verify(phc_hash, password) -> Result<()>
Presets: Mobile (64 MiB, t=3, p=4) | Desktop (256 MiB, t=4, p=8)
Key Derivation (HKDF-SHA256) #
hkdf_derive(ikm, salt?, info, output_len) -> Result<Vec<u8>> (one-shot)
hkdf_extract(ikm, salt?) -> Result<Vec<u8>> (PRK)
hkdf_expand(prk, info, output_len) -> Result<Vec<u8>>
Platform Support #
| Platform | Target | Status |
|---|---|---|
| Android | aarch64-linux-android, armv7-linux-androideabi |
CI-tested |
| iOS | aarch64-apple-ios, aarch64-apple-ios-sim |
CI-tested |
| macOS | aarch64-apple-darwin, x86_64-apple-darwin |
Supported |
| Linux | x86_64-unknown-linux-gnu |
CI-tested |
| Windows | x86_64-pc-windows-msvc |
Supported |
Testing #
Rust unit tests (79 tests including NIST/RFC test vectors):
cd rust && cargo test
Dart integration tests (63 tests across all features, requires a running device/simulator):
cd example
flutter test integration_test/
Tech Stack #
| Component | Version |
|---|---|
| Rust | stable |
| Flutter Rust Bridge | 2.11.1 |
| Dart SDK | ^3.10.8 |
| Flutter SDK | >=3.3.0 |
Rust crates: aes-gcm 0.10, chacha20poly1305 0.10, blake3 1.8, sha3 0.10, argon2 0.5, hkdf 0.12, zstd 0.13, brotli 7.0, zeroize 1.8
Roadmap #
| Feature | Description | Status |
|---|---|---|
| Streaming encryption | Process large files in chunks with progress callbacks | v0.3.0 |
| Compression pipeline | Zstd/Brotli compression integrated into streaming and EVFS | v0.3.0 |
| Encrypted Virtual File System (EVFS) | .vault container with named segments, WAL recovery, shadow index, secure deletion |
v0.3.0 |
| EVFS v2: Defrag & resize | Online defragmentation and vault resizing | Planned |
| EVFS v2: Key rotation | Re-encrypt vault with new master key | Planned |
| Stealth storage | Ephemeral secrets in Rust-managed memory with derived-path obfuscation | Planned |
| Hardware key wrap | Master key in Secure Enclave (iOS) / KeyStore (Android) with biometric unlock | Planned |
Contributing #
See CONTRIBUTING.md for development setup, coding standards, and PR workflow.
License #
MIT. See LICENSE for details.
Copyright (c) 2025 MicroClub-USTHB