Thank you for your interest in contributing to M-Security! This project is built and maintained by the Dev Department of MicroClub at USTHB. This guide covers everything you need to get started.
- Code of Conduct
- Getting Started
- Development Setup
- Project Structure
- Making Changes
- Coding Standards
- Testing
- Submitting a Pull Request
- Security
M-Security aims to be a unified, high-performance security layer for Flutter, making strong data protection simple to use and easy to integrate. It is designed to give developers a reliable foundation for handling sensitive data without sacrificing performance or developer experience.
The project focuses on securing data across its entire lifecycle, including storage, in-app processing, and access, while maintaining a consistent and intuitive API. It also serves as a cross-platform trust layer, bringing platform-specific security features into a single, cohesive interface.
Ultimately, M-Security strives to become a long-term security backbone for Flutter applications, where robust security is built in by default rather than added later.
Contributions to any of these areas are welcome. If you want to work on an upcoming feature, open an issue first to discuss the approach.
By participating in this project, you agree to maintain a respectful and inclusive environment. Be kind, constructive, and professional in all interactions.
- Fork the repository on GitHub.
- Clone your fork locally:
git clone git@github.com:<your-username>/M-Security.git cd M-Security
- Add upstream remote:
git remote add upstream git@github.com:MicroClub-USTHB/M-Security.git
| Tool | Required For |
|---|---|
| Rust (stable) | Crypto core compilation |
| Flutter SDK (stable) | Dart SDK ^3.10.8 |
| flutter_rust_bridge_codegen | FFI binding generation |
Install Rust and FRB codegen:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install flutter_rust_bridge_codegenPlatform-specific tools:
| Platform | Requirements |
|---|---|
| macOS / iOS | Xcode with command line tools (xcode-select --install) |
| Android | Android NDK (r27c recommended, installed via Android Studio) |
| Linux | sudo apt install clang cmake ninja-build pkg-config libgtk-3-dev |
| Windows | Visual Studio Build Tools + LLVM |
# 1. Install Flutter dependencies
flutter pub get
# 2. Build the Rust library (verifies Rust code compiles)
cd rust && cargo build && cd ..
# 3. Generate FFI bindings (Dart to Rust)
flutter_rust_bridge_codegen generate
# 4. Generate Freezed data classes
dart run build_runner build --delete-conflicting-outputs
# 5. Run the example app (requires a device/simulator)
cd example && flutter runM-Security/
├── lib/ # Dart public API
│ ├── m_security.dart # Barrel export (public surface)
│ └── src/
│ ├── encryption/
│ │ ├── aes_gcm.dart # AesGcmService wrapper
│ │ └── chacha20.dart # Chacha20Service wrapper
│ ├── hashing/
│ │ └── argon2.dart # argon2IdHash/Verify with preset defaults
│ ├── kdf/
│ │ └── hkdf.dart # MHKDF wrapper class
│ └── rust/ # Auto-generated FRB bindings (DO NOT EDIT)
│ ├── frb_generated.dart # RustLib.init() entry point
│ ├── api/ # Generated Dart FFI functions
│ └── core/ # Generated Dart types
├── rust/ # Rust crypto core
│ ├── Cargo.toml # Crate config, dependencies, lints
│ └── src/
│ ├── lib.rs # Crate root
│ ├── frb_generated.rs # FRB-generated Rust glue
│ ├── api/ # Public API (scanned by FRB)
│ │ ├── mod.rs
│ │ ├── error.rs # CryptoError enum (thiserror)
│ │ ├── encryption/
│ │ │ ├── mod.rs # CipherHandle, encrypt/decrypt, key gen
│ │ │ ├── aes_gcm.rs # AES-256-GCM implementation
│ │ │ ├── chacha20.rs # ChaCha20-Poly1305 implementation
│ │ │ └── noop.rs # Testing-only cipher (behind `testing` feature)
│ │ ├── hashing/
│ │ │ ├── mod.rs # HasherHandle, blake3_hash, sha3_hash
│ │ │ ├── argon2.rs # Argon2id with presets
│ │ │ ├── blake3.rs # BLAKE3 implementation
│ │ │ └── sha3.rs # SHA-3-256 implementation
│ │ └── kdf/
│ │ ├── mod.rs
│ │ └── hkdf.rs # HKDF-SHA256 (derive, extract, expand)
│ └── core/ # Internal utilities (not exposed to Dart)
│ ├── mod.rs
│ ├── error.rs # CryptoError definition
│ ├── traits.rs # Encryption, Hasher, Kdf traits
│ ├── secret.rs # SecretBuffer with ZeroizeOnDrop
│ ├── rng.rs # CSPRNG (OsRng) key/nonce generation
│ └── format.rs # MSEC format header for encrypted data
├── cargokit/ # Build system: compiles Rust during Flutter build
├── android/ # Android plugin (ffiPlugin + cargokit)
├── ios/ # iOS plugin (CocoaPods + cargokit)
├── macos/ # macOS plugin (CocoaPods + cargokit)
├── linux/ # Linux plugin (CMake + cargokit)
├── windows/ # Windows plugin (CMake + cargokit)
├── example/ # Flutter example app
├── integration_test/ # Dart integration tests
│ ├── aes_gcm_test.dart # AES-256-GCM (6 tests)
│ ├── chacha20_test.dart # ChaCha20-Poly1305 (7 tests)
│ ├── hashing_test.dart # BLAKE3 + SHA-3 (11 tests)
│ ├── argon2_test.dart # Argon2id (6 tests)
│ └── hkdf_test.dart # HKDF-SHA256 with RFC 5869 vectors (14 tests)
├── .github/workflows/ci.yml # CI: lint, test, build (Android, iOS, Linux)
├── flutter_rust_bridge.yaml # FRB codegen config
├── CONTRIBUTING.md
├── RELEASE_GUIDE.md
├── CHANGELOG.md
├── LICENSE # MIT
└── README.md
rust/src/api/contains everything scanned by Flutter Rust Bridge and exposed to Dart. New cryptographic primitives go here.rust/src/core/holds internal Rust utilities not exposed to Dart. It houses theEncryption,Hasher, andKdftraits that all implementations must satisfy, plusSecretBufferfor secure memory.lib/src/rust/is auto-generated by FRB. Never edit these files manually. They are regenerated withflutter_rust_bridge_codegen generate.lib/src/encryption/,hashing/,kdf/are hand-written Dart wrapper services that provide a clean, idiomatic API on top of the generated FFI bindings.lib/m_security.dartis the barrel export. Only types and functions exported here are part of the public API.cargokit/is the build system that compiles Rust code automatically duringflutter build. It integrates with Gradle (Android), CocoaPods (iOS/macOS), and CMake (Linux/Windows).
Create a feature branch from dev (not main):
git checkout dev
git pull upstream dev
git checkout -b <type>/<short-description>Branch types:
| Prefix | Use |
|---|---|
feat/ |
New feature or algorithm |
fix/ |
Bug fix |
refactor/ |
Code restructuring |
docs/ |
Documentation changes |
ci/ |
CI/CD pipeline changes |
test/ |
Test additions or fixes |
- Implement in Rust. Add your module under
rust/src/api/<category>/. - Implement the appropriate trait from
rust/src/core/traits.rs:Encryptionfor ciphers (requiresencrypt,decrypt,algorithm_id)Hasherfor hash functions (requiresupdate,reset,finalize,algorithm_id)Kdffor key derivation (requiresderive,algorithm_id)
- Use
SecretBufferfor all key material (ensures automatic zeroization on drop). - Use
OsRngviacore::rngfor all randomness. Never usethread_rng. - Return
Result<T, CryptoError>. Never useunwrap()(Clippy will reject it). - Write Rust unit tests in the same file using
#[cfg(test)]. - Export the module from the parent
mod.rs. - Regenerate FFI bindings:
flutter_rust_bridge_codegen generate
- Create a Dart wrapper in
lib/src/<category>/following existing patterns. - Export it from
lib/m_security.dart. - Write integration tests in
integration_test/.
If your primitive holds state (like a cipher key or hasher state):
use flutter_rust_bridge::frb;
#[frb(opaque)]
pub struct MyHandle {
inner: Box<dyn MyTrait + Send + Sync>,
}This ensures the handle is never serialized across FFI. Dart holds a pointer only.
- No
unwrap()in FFI-visible code. Enforced by[lints.clippy] unwrap_used = "deny"inCargo.toml. UseResult<T, CryptoError>for all fallible operations.unwrap()is allowed in#[cfg(test)]modules only. - Derive
ZeroizeOnDropon all structs holding key material. - Use
thiserrorfor error types. All errors map toCryptoErrorvariants. panic = "abort"in release. Panics must not cross FFI. This is enforced inCargo.toml's[profile.release].- Run Clippy before committing:
cd rust && cargo clippy --all-targets -- -D warnings
- Format code:
cd rust && cargo fmt
- Follow the Flutter style guide.
- Run the analyzer:
dart analyze lib/ integration_test/
- Format code:
dart format lib/ integration_test/
Follow Conventional Commits:
feat(encryption): add XChaCha20-Poly1305 cipher
fix(argon2): correct memory allocation on mobile preset
docs: update README with new algorithm table
test(hkdf): add RFC 5869 test case 3
ci: add Windows build job
Keep commits atomic, with one logical change per commit.
cd rust && cargo testThere are 79 unit tests covering all algorithms, including NIST and RFC test vectors (RFC 8439 for ChaCha20, RFC 5869 for HKDF).
Integration tests require a running device or simulator. From the project root:
cd example
flutter test integration_test/aes_gcm_test.dart
flutter test integration_test/chacha20_test.dart
flutter test integration_test/hashing_test.dart
flutter test integration_test/argon2_test.dart
flutter test integration_test/hkdf_test.dartThere are 44 integration tests across 5 files covering all features.
All pull requests must pass the CI pipeline (.github/workflows/ci.yml), which runs:
| Job | Runner | What it does |
|---|---|---|
| Rust | ubuntu-latest |
cargo clippy -- -D warnings + cargo test |
| Dart | ubuntu-latest |
FRB codegen + build_runner + dart analyze |
| Android | ubuntu-latest |
Full APK build (ARM64 + ARMv7, NDK r27c) |
| iOS | macos-latest |
Simulator debug build (ARM64 + ARM64-sim) |
| Linux | ubuntu-latest |
Release build with GTK-3 |
The CI is triggered on pushes and PRs to main and dev branches.
- Ensure all tests pass locally:
cd rust && cargo clippy --all-targets -- -D warnings && cargo test && cd .. dart analyze lib/ integration_test/
- Push your branch to your fork:
git push origin <your-branch>
- Open a PR against the
devbranch on the upstream repository. - Fill in the PR description with:
- A clear description of the change
- Related issue numbers (if any)
- Testing steps
- Wait for CI to pass and for a maintainer review.
- Address review feedback with additional commits (do not force-push during review).
- Rust code compiles without warnings (
cargo clippy --all-targets -- -D warnings) - Dart code analyzes clean (
dart analyze lib/ integration_test/) - All existing Rust tests pass (
cargo test) - All existing integration tests pass
- New tests added for new functionality
- FRB bindings regenerated if Rust API changed (
flutter_rust_bridge_codegen generate) - Public API exported from
lib/m_security.dartif adding new user-facing types - Documentation updated if public API changed
-
CHANGELOG.mdupdated under an## Unreleasedsection - Commit messages follow Conventional Commits
If you discover a security vulnerability, do not open a public issue. Instead, report it privately using GitHub Security Advisories.
Cryptographic code requires extra scrutiny. All contributions touching crypto must follow these rules:
- Never introduce
unsafeblocks without justification and review. - All key material must use
SecretBuffer(rust/src/core/secret.rs) which derivesZeroizeOnDrop. - Never expose raw key bytes across the FFI boundary. Use
#[frb(opaque)]handles. - Use
OsRng(viacore::rng) for all random number generation. Never usethread_rngor similar. - All errors must be explicit. Return
Result<T, CryptoError>, neverunwrap(). - Include test vectors from official standards (NIST, RFC) when implementing new algorithms.