Skip to content

Commit e6f3016

Browse files
authored
Merge pull request #119 from MicroClub-USTHB/78-evfs-key-management
EVFS: key rotation, vault export/import, and Dart wrappers
2 parents d289a45 + 0b11cfe commit e6f3016

20 files changed

Lines changed: 3328 additions & 75 deletions

File tree

.github/workflows/ci.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
with:
4242
channel: stable
4343
- uses: dtolnay/rust-toolchain@stable
44-
- run: cargo install flutter_rust_bridge_codegen
44+
- run: cargo install flutter_rust_bridge_codegen@2.11.1
4545
- run: flutter pub get
4646
- run: flutter_rust_bridge_codegen generate
4747
- run: dart run build_runner build --delete-conflicting-outputs
@@ -62,7 +62,7 @@ jobs:
6262
- uses: nttld/setup-ndk@v1
6363
with:
6464
ndk-version: r27c
65-
- run: cargo install flutter_rust_bridge_codegen
65+
- run: cargo install flutter_rust_bridge_codegen@2.11.1
6666
- run: flutter pub get
6767
- run: flutter_rust_bridge_codegen generate
6868
- run: dart run build_runner build --delete-conflicting-outputs
@@ -80,7 +80,7 @@ jobs:
8080
- uses: dtolnay/rust-toolchain@stable
8181
with:
8282
targets: aarch64-apple-ios,aarch64-apple-ios-sim
83-
- run: cargo install flutter_rust_bridge_codegen
83+
- run: cargo install flutter_rust_bridge_codegen@2.11.1
8484
- run: flutter pub get
8585
- run: flutter_rust_bridge_codegen generate
8686
- run: dart run build_runner build --delete-conflicting-outputs
@@ -97,7 +97,7 @@ jobs:
9797
channel: stable
9898
- uses: dtolnay/rust-toolchain@stable
9999
- run: sudo apt-get update && sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev
100-
- run: cargo install flutter_rust_bridge_codegen
100+
- run: cargo install flutter_rust_bridge_codegen@2.11.1
101101
- run: flutter pub get
102102
- run: flutter_rust_bridge_codegen generate
103103
- run: dart run build_runner build --delete-conflicting-outputs

CHANGELOG.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,35 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## Unreleased
8+
## v0.3.4 - 2026-04-04
99

1010
### Added
1111

12-
### Changed
12+
- Master key rotation via `vault_rotate_key()` — re-encrypts all vault data under a new key using atomic copy-to-new-vault + rename strategy. Crash recovery: stale `.rotating` file cleaned on `vault_open()`.
13+
- Vault export via `vault_export()` — produces a self-contained `.mvex` encrypted archive with BLAKE3 integrity trailer, ephemeral export key AEAD-wrapped with caller's wrapping key, and per-segment re-encryption.
14+
- Vault import via `vault_import()` — reads `.mvex` archive, creates new vault re-encrypted under a local master key. Validates header, unwraps export key, verifies per-segment BLAKE3 checksums and trailer integrity.
15+
- `ImportFailed`, `ExportFailed`, and `KeyRotationFailed` error variants in `CryptoError`.
16+
- Dart `VaultService.rotateKey()`, `VaultService.export()`, and `VaultService.importVault()` static methods.
17+
- 7 Dart integration tests for key management (rotation roundtrip, old key rejection, export-import roundtrip, wrong wrapping key, 1MB+ segment, multiple rotations, rotate-then-export-import).
18+
- 26 Rust tests for key management (10 rotation + 7 export + 9 import).
19+
- Example app Key Management section with Rotate Key, Export, and Import buttons.
20+
- CI workflow pinned `flutter_rust_bridge_codegen` to v2.11.1 to match runtime dependency.
21+
22+
### Security
23+
24+
- Old sub-keys zeroized immediately after rotation via `ZeroizeOnDrop`.
25+
- Export wrapping uses AAD `b"msec-export-key-wrap"` for domain separation.
26+
- Archive format authenticated: per-segment AAD (segment name) + BLAKE3 trailer covering all preceding bytes.
27+
- `vault_write` plaintext wrapped in `Zeroizing<Vec<u8>>` — guarantees zeroization on all exit paths including `encrypt_segment` failure.
28+
- Import hardened: `u64` to `usize` safe cast via `try_from` (32-bit overflow protection), OOM guard in `u64` arithmetic with `saturating_add`, `.lock` file cleanup in error paths, segment name validation (1-255 bytes), `segment_count` sanity bound (100K), unknown compression byte rejection.
29+
- Atomic rename before lock release in rotation (closes race window).
1330

1431
### Fixed
1532

33+
- `unwrap()` in `archive.rs` replaced with `map_err()` for clippy compliance.
34+
- `from_bytes` errors remapped to `ImportFailed` at import call sites.
35+
- Example app lint: replaced `src/` imports with public `m_security.dart` re-exports.
36+
1637
## [v0.3.3](https://github.com/MicroClub-USTHB/M-Security/releases/tag/v0.3.3) - 2026-03-28
1738

1839
### Added

README.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Built and maintained by the **Dev Department** of [MicroClub](https://github.com
2929
| **Password Hashing** | Argon2id | PHC winner, Mobile and Desktop presets |
3030
| **Key Derivation** | HKDF-SHA256 | RFC 5869, extract-then-expand with domain separation |
3131
| **Encrypted VFS (EVFS)** | `.vault` container | Named segments, WAL recovery, shadow index, secure deletion |
32+
| **Key Management** | Rotation, export/import | Atomic re-encryption, `.mvex` portable archives |
3233
| **Zero-Copy I/O** | mmap + DCO codec | Memory-mapped vault reads, zero-copy Rust-to-Dart transfers |
3334

3435
**Security by design:**
@@ -48,7 +49,7 @@ Add to your `pubspec.yaml`:
4849

4950
```yaml
5051
dependencies:
51-
m_security: ^0.3.3
52+
m_security: ^0.3.4
5253
```
5354
5455
Then run:
@@ -224,6 +225,31 @@ await VaultService.delete(handle: handle, name: 'secret.txt');
224225
await VaultService.close(handle: handle);
225226
```
226227

228+
#### Key Management
229+
230+
```dart
231+
// Rotate master key (re-encrypts all segments atomically)
232+
final newHandle = await VaultService.rotateKey(handle: handle, newKey: newKey);
233+
// Old handle is invalidated; use newHandle from here
234+
235+
// Export vault to portable encrypted archive
236+
await VaultService.export(
237+
handle: handle,
238+
wrappingKey: wrappingKey,
239+
exportPath: '/path/to/backup.mvex',
240+
);
241+
242+
// Import vault from archive (creates new vault with fresh key)
243+
final imported = await VaultService.importVault(
244+
archivePath: '/path/to/backup.mvex',
245+
wrappingKey: wrappingKey,
246+
destPath: '/path/to/restored.vault',
247+
newMasterKey: localKey,
248+
algorithm: 'aes-256-gcm',
249+
capacityBytes: 10 * 1024 * 1024,
250+
);
251+
```
252+
227253
#### Vault Maintenance
228254

229255
```dart
@@ -366,7 +392,7 @@ flutter test integration_test/
366392
| **EVFS v2: Defrag & resize** | Online defragmentation, vault resizing, health diagnostics | v0.3.1 |
367393
| **EVFS v2: Streaming I/O** | Constant-memory streaming reads/writes, per-chunk AEAD, progress callbacks | v0.3.2 |
368394
| **Zero-copy FFI optimization** | mmap vault reads, DCO codec, release profile hardening, symbol stripping | v0.3.3 |
369-
| **EVFS v2: Key rotation** | Re-encrypt vault with new master key | Planned |
395+
| **EVFS v2: Key management** | Key rotation, vault export/import (`.mvex` archives), Dart wrappers | v0.3.4 |
370396
| **Stealth storage** | Ephemeral secrets in Rust-managed memory with derived-path obfuscation | Planned |
371397
| **Hardware key wrap** | Master key in Secure Enclave (iOS) / KeyStore (Android) with biometric unlock | Planned |
372398

0 commit comments

Comments
 (0)