Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,28 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased
## v0.3.3 - 2026-03-27

### Added

- Zero-copy vault reads via `memmap2` memory-mapped I/O — `vault_read` and `vault_read_stream` now slice directly into mapped file pages instead of allocating heap buffers with `read_exact`.
- `VaultMmap` wrapper with `mlock()` on unix to pin ciphertext pages in RAM and prevent swap-to-disk. Graceful fallback to heap reads when mmap fails (32-bit targets, low `mlock` limits).
- mmap invalidation/recreation after every vault mutation (write, delete, defrag, resize).
- ELF linker version script (`ffi-exports.map`) restricting Android/Linux `.so` dynamic symbol table to FRB FFI symbols only — hides `#[no_mangle]` symbols leaked by dependencies.
- `build.rs` for conditional version script application on Android/Linux cdylib builds.

### Changed

### Fixed
- Switched all 50 FRB functions from SSE to CST+DCO codec via `full_dep: true` — `Vec<u8>` returns now use `allo-isolate` `ExternalTypedData` (pointer transfer, no memcpy) instead of SSE serialization.
- Release profile hardened: `lto = "fat"`, `codegen-units = 1`, `strip = "symbols"`, `opt-level = 3`.
- `VaultHandle` field order: `mmap` before `file` so `munlock`/`munmap` runs while the fd is still open.

### Security

- Symbol stripping removes internal Rust function names from release binaries — `nm -D` shows only FRB entry points and libc on ELF targets.
- `mlock()` prevents OS from swapping mmap'd ciphertext pages to disk swap.
- Fewer intermediate `Vec<u8>` copies means shorter plaintext residency in memory.
- ZeroizeOnDrop behavior preserved — no regression from zero-copy refactoring.

## [v0.3.2](https://github.com/MicroClub-USTHB/M-Security/releases/tag/v0.3.2) - 2026-03-26

Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ Built and maintained by the **Dev Department** of [MicroClub](https://github.com
| **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 |
| **Zero-Copy I/O** | mmap + DCO codec | Memory-mapped vault reads, zero-copy Rust-to-Dart transfers |

**Security by design:**

Expand All @@ -38,14 +39,16 @@ Built and maintained by the **Dev Department** of [MicroClub](https://github.com
- 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`:

```yaml
dependencies:
m_security: ^0.3.2
m_security: ^0.3.3
```

Then run:
Expand Down Expand Up @@ -329,13 +332,13 @@ hkdf_expand(prk, info, output_len) -> Result<Vec<u8>>

## Testing

**Rust unit tests** (317 tests including EVFS streaming and defrag):
**Rust unit tests** (331 tests including EVFS streaming and defrag):

```bash
cd rust && cargo test
```

**Dart integration tests** (63 tests across all features, requires a running device/simulator):
**Dart integration tests** (76 tests across all features, requires a running device/simulator):

```bash
cd example
Expand All @@ -351,7 +354,7 @@ flutter test integration_test/
| 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
**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, `memmap2` 0.9

## Roadmap

Expand All @@ -362,6 +365,7 @@ flutter test integration_test/
| **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, vault resizing, health diagnostics | v0.3.1 |
| **EVFS v3: Streaming I/O** | Constant-memory streaming reads/writes, per-chunk AEAD, progress callbacks | v0.3.2 |
| **Zero-copy FFI optimization** | mmap vault reads, DCO codec, release profile hardening, symbol stripping | v0.3.3 |
| **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 |
Expand Down
1 change: 1 addition & 0 deletions flutter_rust_bridge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ rust_input: crate::api
rust_root: rust/
dart_output: lib/src/rust
enable_lifetime: true
full_dep: true
rust_features:
- compression
2 changes: 1 addition & 1 deletion lib/src/rust/api/encryption.dart
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,5 @@ Future<String> encryptionAlgorithmId({required CipherHandle cipher}) => RustLib
.api
.crateApiEncryptionEncryptionAlgorithmId(cipher: cipher);

// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<CipherHandle>>
// Rust type: RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<CipherHandle>>
abstract class CipherHandle implements RustOpaqueInterface {}
6 changes: 4 additions & 2 deletions lib/src/rust/api/evfs/types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import '../../frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';

// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `eq`, `fmt`
// These functions are ignored because they are not marked as `pub`: `new`, `refresh_mmap`, `slice`
// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `VaultMmap`
// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `drop`, `eq`, `fmt`

// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<VaultHandle>>
// Rust type: RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<VaultHandle>>
abstract class VaultHandle implements RustOpaqueInterface {
/// Compute health information from the in-memory index only (no file I/O or WAL writes).
Future<VaultHealthInfo> health();
Expand Down
2 changes: 1 addition & 1 deletion lib/src/rust/api/hashing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,5 @@ Future<Uint8List> blake3Hash({required List<int> data}) =>
Future<Uint8List> sha3Hash({required List<int> data}) =>
RustLib.instance.api.crateApiHashingSha3Hash(data: data);

// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<HasherHandle>>
// Rust type: RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<HasherHandle>>
abstract class HasherHandle implements RustOpaqueInterface {}
Loading
Loading