MCPcopy Index your code
hub / github.com/MicroClub-USTHB/M-Security

github.com/MicroClub-USTHB/M-Security @v0.3.5

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.3.5 ↗ · + Follow
1,015 symbols 4,171 edges 79 files 154 documented · 15% updated 2mo agov0.3.5 · 2026-04-10★ 581 open issues
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

M-Security Logo

M-Security

pub package pub points pub downloads Platforms CI License: MIT

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
Segment Enhancements Metadata, rename, parallel Per-segment key-value tags, rename without re-encryption, concurrent reads
Key Management Rotation, export/import Atomic re-encryption, .mvex portable archives
Zero-Copy I/O mmap + DCO codec Memory-mapped vault reads, zero-copy Rust-to-Dart transfers

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 FFI
  • clippy::unwrap_used = "deny", ensuring all operations return Result<T, CryptoError>
  • Release builds strip all symbols except FRB entry points (LTO + ELF version script)
  • mlock() pins mmap'd ciphertext pages to prevent swap-to-disk (unix)

Installation

Add to your pubspec.yaml:

dependencies:
  m_security: ^0.3.5

Then run:

flutter pub get

Prerequisites

M-Security compiles Rust code during the Flutter build. You need:

  • Rust toolchain (stable):

bash 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-dev
Windows 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 10 MB vault with AES-256-GCM
final handle = await VaultService.create(
  path: '/path/to/my.vault',
  key: key,
  algorithm: 'aes-256-gcm',
  capacityBytes: 10 * 1024 * 1024,
);

// Write a segment (with optional compression and metadata)
await VaultService.write(
  handle: handle,
  name: 'secret.txt',
  data: utf8.encode('confidential'),
  compression: CompressionConfig(algorithm: CompressionAlgorithm.zstd),
  metadata: {'mime': 'text/plain', 'author': 'alice'},
);

// Read it back (decompression is automatic, metadata included)
final result = await VaultService.read(handle: handle, name: 'secret.txt');
print(result.data);       // decrypted bytes
print(result.metadata);   // {'mime': 'text/plain', 'author': 'alice'}

// List segments, delete, close
final segments = await VaultService.list(handle: handle);
await VaultService.delete(handle: handle, name: 'secret.txt');
await VaultService.close(handle: handle);

Key Management

// Rotate master key (re-encrypts all segments atomically)
final newHandle = await VaultService.rotateKey(handle: handle, newKey: newKey);
// Old handle is invalidated; use newHandle from here

// Export vault to portable encrypted archive
await VaultService.export(
  handle: handle,
  wrappingKey: wrappingKey,
  exportPath: '/path/to/backup.mvex',
);

// Import vault from archive (creates new vault with fresh key)
final imported = await VaultService.importVault(
  archivePath: '/path/to/backup.mvex',
  wrappingKey: wrappingKey,
  destPath: '/path/to/restored.vault',
  newMasterKey: localKey,
  algorithm: 'aes-256-gcm',
  capacityBytes: 10 * 1024 * 1024,
);

Segment Enhancements

// Rename a segment (index-only, no re-encryption)
await VaultService.renameSegment(handle: handle, oldName: 'draft.txt', newName: 'final.txt');

// Explicit flush — persist in-memory index to disk
await VaultService.flush(handle: handle);

// Parallel read — decrypt multiple segments concurrently
final results = await VaultService.readParallel(
  handle: handle,
  names: ['file1.bin', 'file2.bin', 'file3.bin'],
);
for (final r in results) {
  if (r.error != null) print('${r.name}: failed — ${r.error}');
  else print('${r.name}: ${r.data.length} bytes');
}

Vault Maintenance

// Health check (read-only, no I/O)
final health = await VaultService.health(handle: handle);
print('Consistent: ${health.isConsistent}');
print('Fragmentation: ${(health.fragmentationRatio * 100).toStringAsFixed(1)}%');

// Defragment — compact segments, coalesce free space (WAL-protected)
final result = await VaultService.defragment(handle: handle);
print('Moved ${result.segmentsMoved} segments, reclaimed ${result.bytesReclaimed} bytes');

// Resize vault capacity (grow or shrink)
await VaultService.resize(handle: handle, newCapacityBytes: 20 * 1024 * 1024);

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

M-Security Architecture

Key design decisions:

  • Opaque handles. CipherHandle and HasherHandle are #[frb(opaque)]. Dart holds a pointer, never raw key bytes.
  • Trait objects. Box<dyn Encryption> and Box<dyn Hasher> with Send + Sync + 'static enable runtime algorithm selection.
  • SecretBuffer. All key material is wrapped in SecretBuffer which derives ZeroizeOnDrop. Memory is zeroed when handles are dropped.
  • No panics across FFI. panic = "abort" in release profile. All FFI functions return Result<T, CryptoError>.
  • Format headers. Encrypted data includes a MSEC magic 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-and

Extension points exported contracts — how you extend this code

Encryption (Interface)
(no doc) [3 implementers]
rust/src/core/traits.rs
CompressorOp (Interface)
(no doc) [3 implementers]
rust/src/core/compression/streaming.rs
DecompressorOp (Interface)
(no doc) [3 implementers]
rust/src/core/compression/streaming.rs
Hasher (Interface)
(no doc) [2 implementers]
rust/src/core/traits.rs
AssertSync (Interface)
(no doc) [1 implementers]
rust/src/api/evfs/tests/parallel.rs

Core symbols most depended-on inside this repo

vault_close
called by 172
rust/src/api/evfs/mod.rs
vault_write
called by 163
rust/src/api/evfs/mod.rs
len
called by 144
rust/src/core/secret.rs
vault_read
called by 86
rust/src/api/evfs/mod.rs
as_bytes
called by 81
rust/src/core/secret.rs
find
called by 61
rust/src/core/evfs/format.rs
data_region_offset
called by 29
rust/src/core/evfs/format.rs
dummy_checksum
called by 29
rust/src/core/evfs/format.rs

Shape

Function 777
Method 149
Class 77
Enum 6
Interface 6

Languages

Rust95%
C++5%
Kotlin1%

Modules by API surface

rust/src/frb_generated.rs218 symbols
rust/src/core/evfs/format.rs94 symbols
rust/src/core/evfs/segment.rs62 symbols
rust/src/core/streaming.rs48 symbols
rust/src/core/evfs/wal.rs39 symbols
rust/src/api/streaming/tests.rs36 symbols
rust/src/api/evfs/tests/streaming.rs33 symbols
rust/src/api/evfs/tests/export_import.rs30 symbols
rust/src/api/evfs/mod.rs29 symbols
rust/src/api/encryption/chacha20.rs24 symbols
rust/src/api/encryption/aes_gcm.rs23 symbols
example/windows/runner/win32_window.cpp23 symbols

For agents

$ claude mcp add M-Security \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact