secure-gate
Zero-cost, no_std-compatible secure wrappers for secrets — stack for fixed-size, heap for dynamic.
Features
| Feature | Effect |
|---|---|
zeroize |
Enables wiping + auto-drop zeroing (on by default) |
serde |
Serialization support |
no_std+alloccompatible.- Redacted
Debug. - Test coverage includes zero-cost, wiping, ergonomics, serde, macros.
Memory Safety Guarantees (when zeroize enabled):
- Fixed-size secrets (
Fixed<T>) usezeroize::Zeroizing<T>— stack-allocated, auto-zeroed. - Dynamic secrets (
Dynamic<T>) usesecrecy::SecretBox<T>— heap-allocated, leak-resistant. - On drop or
zeroize(),Vec<u8>andStringsecrets are completely deallocated (not just zeroed).- Verified via unsafe inspection: capacity drops to 0, buffer is freed.
- Stronger than full-capacity wiping — no slack memory remains.
Internal Usage of Dependencies:
Fixed<T>useszeroize::Zeroizing<T>for stack-allocated, auto-zeroing fixed-size secrets.Dynamic<T>usessecrecy::SecretBox<T>for heap-allocated, leak-protected dynamic secrets.- Both forward
ZeroizeOnDropandZeroizefor seamless integration.
Fuzzing Configuration
| Target | Description | Runtime per CI run |
|---|---|---|
clone |
init_with, into_inner, scoped zeroization |
60 minutes |
expose |
Memory access + finish_mut |
60 minutes |
mut |
Unbounded expose_mut() mutation stress |
60 minutes |
parsing |
FromStr parsing |
60 minutes |
serde |
JSON + bincode deserialization from untrusted input | 60 minutes |
- 5 libFuzzer targets
- 240 CPU minutes per nightly run
- Runs on GitHub Actions (ubuntu-latest, nightly toolchain)
- Artifacts uploaded on every run
Installation
[]
= "0.5.0"
With serde:
= { = "0.5.0", = ["serde"] }
Quick Start
use ;
// Fixed-size key (stack when zeroize off)
fixed_alias!;
let key: Aes256Key = .into;
assert_eq!;
key = 1; // DerefMut
// Dynamic password (heap, full protection)
let mut pw = new;
assert_eq!;
assert_eq!; // Deref
pw.push;
pw.finish_mut; // shrink_to_fit
// Macros
let iv = secure!;
assert_eq!;
// Extraction
let extracted = key.into_inner;
assert_eq!;
Example Aliases
Use fixed_alias! for fixed-size types and dynamic_alias! for dynamic types. These generate self-documenting aliases.
Fixed-Size (Stack-Optimized)
use fixed_alias;
// Crypto keys
fixed_alias!;
fixed_alias!;
fixed_alias!;
// Nonces and IVs
fixed_alias!;
fixed_alias!;
fixed_alias!;
fixed_alias!;
// Salts
fixed_alias!;
// Usage
let key: Aes256Key = .into;
let iv = new;
Dynamic-Size (Heap-Optimized)
use dynamic_alias;
// Strings and passwords
dynamic_alias!;
dynamic_alias!;
// Byte vectors
dynamic_alias!;
dynamic_alias!;
// Usage
let pw: Password = new;
let token: Token = new_boxed;
assert_eq!;
pw.push; // DerefMut
assert_eq!;
Migration from v0.4.3
v0.5.0 is a clean break from v0.4.3's experimental API.
SecureGate<T>→Fixed<T>(fixed-size) orDynamic<T>(dynamic).ZeroizeMode/new_full_wipe→ Removed;zeroizehandles wiping.SecurePassword→Dynamic<String>.expose_secret()→Deref(e.g.,&*secret).unsafe-wipe→ Removed; safe by default.
Example migration:
// v0.4.3
let pw: SecurePassword = "hunter2".into;
pw.expose_secret_mut.push;
// v0.5.0
let mut pw = new;
pw.push;
All v0.4.3 code breaks — this is intentional for the clean redesign.
Changelog
See CHANGELOG.md for full history.
License
Dual-licensed under MIT OR Apache-2.0, at your option.