secure-gate
no_std-compatible wrappers for sensitive data with explicit exposure requirements.
Fixed<T>— Stack-allocated wrapperDynamic<T>— Heap-allocated wrapperFixedRandom<N>— Stack-allocated cryptographically secure random bytesDynamicRandom— Heap-allocated cryptographically secure random bytesCloneableArray<const N: usize>— Cloneable fixed-size stack secret ([u8; N])CloneableString— Cloneable heap-allocated text secret (String)CloneableVec— Cloneable heap-allocated binary secret (Vec<u8>)HexString— Validated lowercase hexadecimal string wrapperBase64String— Validated URL-safe base64 string wrapper (no padding)Bech32String— Validated Bech32/Bech32m string wrapper
Memory containing secrets is zeroed on drop, including spare capacity where applicable (when zeroize is enabled).
Access requires an explicit .expose_secret() (or .expose_secret_mut()) call — no Deref or implicit paths.
Installation
[]
= "0.7.0-rc.6"
Basic configuration includes zeroize and ct-eq (via the secure meta-feature) for secure memory handling and constant-time equality.
Recommended for most users (secure defaults):
= "0.7.0-rc.6" # default enables "secure"
Batteries-included (all optional features):
= { = "0.7.0-rc.6", = ["full"] }
Constrained / minimal builds (no zeroization or ct-eq — strongly discouraged for production):
= { = "0.7.0-rc.6", = false, = ["insecure"] }
Features
| Feature | Description |
|---|---|
secure (default) |
Enables zeroize + ct-eq — secure memory wiping and constant-time equality (recommended) |
zeroize |
Memory zeroing on drop + opt-in safe cloning (requires zeroize crate) |
ct-eq |
Constant-time equality checks to prevent timing attacks (requires subtle crate) |
rand |
Random generation (FixedRandom<N>::generate(), DynamicRandom::generate()) |
encoding |
All encoding support (encoding-hex, encoding-base64, encoding-bech32) |
encoding-hex |
Hex encoding + HexString + random hex methods |
encoding-base64 |
Base64String (URL-safe, no padding) |
encoding-bech32 |
Bech32String (Bech32/Bech32m, mixed-case input, lowercase storage) |
full |
Meta-feature enabling all optional features (includes secure) |
insecure |
Explicit opt-out for no-default-features builds (disables zeroize and ct-eq) — not recommended for production |
no_std + alloc compatible. Features add no overhead when unused.
Security Model & Design Philosophy
secure-gate prioritizes auditability and explicitness over implicit convenience.
All secret access requires an explicit .expose_secret() (or .expose_secret_mut()) call — making exposures grep-able and preventing hidden leaks.
These calls are zero-cost #[inline(always)] reborrows (fully elided by the optimizer). The explicitness is deliberate "theater" for humans and auditors, with no runtime overhead.
Quick Start
use ;
// Recommended: semantic aliases for clarity
fixed_alias!; // Fixed-size byte secret
dynamic_alias!; // Heap string secret
// Create secrets
let key: Aes256Key = .into; // From array/slice
let mut pw: Password = "hunter2".into; // From &str/String
// Access (zero-cost)
assert_eq!;
let key_bytes = key.expose_secret; // &[u8; 32]
// Mutable access
pw.expose_secret_mut.push;
// See dedicated sections below for:
// - Opt-In Safe Cloning (`zeroize` feature)
// - Random Generation (`rand` feature)
// - Encoding (`encoding-*` features)
// - Constant-Time Equality (`ct-eq` feature)
Opt-In Safe Cloning
Cloning secret data is opt-in and only available when the zeroize feature is enabled.
This ensures cloning is deliberate, auditable, and always paired with secure zeroization.
Key mechanism: The CloneSafe marker trait.
To enable safe cloning:
- Implement or derive
Clone - Implement or derive
Zeroize - Implement
CloneSafe(blanket implementations exist for primitives and fixed arrays)
This prevents accidental deep copies that could bypass zeroization.
Pre-Built Cloneable Types
| Type | Allocation | Inner Data | Typical Use Case |
|---|---|---|---|
CloneableArray<const N: usize> |
Stack | [u8; N] |
Fixed-size keys, nonces |
CloneableString |
Heap | String |
Passwords, tokens, API keys |
CloneableVec |
Heap | Vec<u8> |
Variable-length binary secrets |
use ;
Recommended: Semantic Aliases
use ;
Minimizing Stack Exposure
Use init_with / try_init_with when reading from untrusted sources:
use CloneableString;
Custom Cloneable Types
Note: Custom implementations of CloneSafe are possible but discouraged — stick to the pre-baked CloneableArray, CloneableString, or CloneableVec types unless you have a strong justification. Improper impls can undermine the crate's cloning guarantees.
use CloneSafe;
Random Generation
FixedRandom<N> can only be constructed via cryptographically secure RNG.
Direct generation is also available:
Encoding
Encoding requires explicit .expose_secret(). Invalid inputs to .new() are zeroed when zeroize is enabled.
Constant-Time Equality
Available on Fixed<[u8; N]> and Dynamic<T> where T: AsRef<[u8]>.
Security Checklist
To maximize the security of your application when using secure-gate, adhere to these guidelines:
- Use secure defaults: Rely on the default feature set (
secure) for automatic memory wiping (zeroize) and constant-time equality (ct-eq). Avoid--no-default-featuresunless you have a strong reason (e.g., constrained embedded environments). - Pre-validate encoding inputs: For Bech32 and other encodings, validate inputs (e.g., HRPs) upfront. Use
try_*methods (e.g.,try_to_bech32) and handle errors properly to avoid issues from malformed data. - Prefer constant-time comparisons: Use
.ct_eq()for all sensitive equality checks to prevent timing attacks. - Minimize secret exposures: Audit your code for
.expose_secret()calls; keep them minimal, logged, and justified. Avoid unnecessary or prolonged exposures. - Restrict cloning: Only clone when necessary. Prefer built-in
Cloneable*types; be cautious with customCloneSafeimplementations. - Conservative feature usage: Enable only the features you need (e.g., specific encodings) to reduce attack surface.
- Regular review: Periodically audit your secret handling logic, especially after dependency updates.
Macros
All macros require explicit visibility (e.g., pub, pub(crate), or none for private).
Basic Aliases
use ;
fixed_alias!; // Fixed<[u8; 32]>
dynamic_alias!; // Dynamic<String>
Generic Aliases
For reusable or library-provided secret types:
use ;
fixed_generic_alias!;
dynamic_generic_alias!; // Vec<u8> can be any type
Custom doc strings (optional):
use ;
fixed_generic_alias!;
dynamic_generic_alias!;
Random-Only Fixed Aliases (rand feature)
These macros create type aliases to Fixed<[u8; N]>, Dynamic<T>, FixedRandom<N>, or their generic counterparts, inheriting all methods and security guarantees.
Memory Guarantees (zeroize enabled)
| Type | Allocation | Auto-zero | Full wipe | Slack eliminated | Notes |
|---|---|---|---|---|---|
Fixed<T> |
Stack | Yes | Yes | Yes (no heap) | |
Dynamic<T> |
Heap | Yes | Yes | No (until drop) | Use shrink_to_fit() |
FixedRandom<N> |
Stack | Yes | Yes | Yes | |
DynamicRandom |
Heap | Yes | Yes | No (until drop) | |
HexString |
Heap | Yes (invalid input) | Yes | No (until drop) | Validated hex |
Base64String |
Heap | Yes (invalid input) | Yes | No (until drop) | Validated base64 |
Bech32String |
Heap | Yes (invalid input) | Yes | No (until drop) | Validated Bech32/Bech32m |
Performance
Wrappers add no runtime overhead compared to raw types in benchmarks.
Changelog
License
MIT OR Apache-2.0