secure-gate
Zero-cost, no_std-compatible wrappers for handling sensitive data in memory.
Fixed<T>– stack-allocated, zero-cost wrapper.Dynamic<T>– heap-allocated wrapper with full.into()ergonomics.- When the
zeroizefeature is enabled,FixedZeroizing<T>andDynamicZeroizing<T>provide automatic zeroing on drop.
Now with conversions — safe, explicit, and still the most ergonomic secret conversions in Rust.
Installation
[]
= "0.5.9"
Recommended (maximum safety + ergonomics):
= { = "0.5.9", = ["zeroize", "rand", "conversions"] }
Features
| Feature | Description |
|---|---|
zeroize |
Automatic memory wiping on drop — strongly recommended |
rand |
SecureRandomExt::random() — cryptographically secure key generation |
conversions |
Safe .to_hex(), .to_base64url(), .ct_eq() — requires explicit .expose_secret() since v0.5.9 |
serde |
Optional serialization (deserialization intentionally disabled on Dynamic<T> for security) |
Works in no_std + alloc. Only pay for what you use.
Quick Start
use ;
fixed_alias!;
fixed_alias!;
dynamic_alias!;
// Cryptographically secure random keys
// Secure conversions — explicit exposure required (v0.5.9+)
// Heap secrets — still pure joy
let pw: Password = "hunter2".into;
assert_eq!;
Secure Conversions — conversions feature (v0.5.9+)
Why .expose_secret() is required
Starting with v0.5.9, all conversion methods live on the exposed &[u8] slice. This guarantees:
- Every secret exposure is grep-able and review-visible
- no accidental silent leaks
- full compatibility with the
secrecy/zeroizeecosystem philosophy
Old direct methods (e.g. key.to_hex()) are deprecated and will be removed in v0.6.0.
Memory Guarantees (zeroize enabled)
| Type | Allocation | Auto-zero | Full wipe | Slack eliminated | Notes |
|---|---|---|---|---|---|
Fixed<T> |
Stack | Yes | Yes | Yes (no heap) | Zero-cost |
Dynamic<T> |
Heap | Yes | Yes | No (until drop) | Use finish_mut() to shrink |
FixedZeroizing<T> |
Stack | Yes | Yes | Yes | RAII wrapper |
DynamicZeroizing<T> |
Heap | Yes | Yes | No (until drop) | SecretBox prevents copies |
Important: DynamicZeroizing<T> uses .expose_secret() — no Deref.
Macros
// Fixed-size secrets
secure! // → Fixed<[u8; 32]>
// Heap secrets
secure! // → Dynamic<String>
secure! // → Dynamic<Vec<u8>>
// Type aliases — the recommended way
fixed_alias!
dynamic_alias!
Example Aliases
fixed_alias!;
fixed_alias!;
dynamic_alias!;
dynamic_alias!;
Zero-cost — proven on real hardware
| Implementation | Median time | Overhead vs raw |
|---|---|---|
raw [u8; 32] |
~460 ps | — |
Fixed<[u8; 32]> |
~460 ps | +28 ps |
fixed_alias!(Key, 32) |
~475 ps | +13 ps |
Overhead is < 0.1 CPU cycles — indistinguishable from raw arrays.
Migration from v0.5.8
If you were using the conversions feature:
- let hex = key.to_hex();
+ let hex = key.expose_secret().to_hex();
The old methods are deprecated and will be removed in v0.6.0.
Changelog
License
MIT OR Apache-2.0