secure-gate 0.5.0

Zero-cost secure wrappers for secrets — stack for fixed, heap for dynamic
Documentation

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 + alloc compatible.
  • Redacted Debug.
  • Test coverage includes zero-cost, wiping, ergonomics, serde, macros.

Memory Safety Guarantees (when zeroize enabled):

  • Fixed-size secrets (Fixed<T>) use zeroize::Zeroizing<T> — stack-allocated, auto-zeroed.
  • Dynamic secrets (Dynamic<T>) use secrecy::SecretBox<T> — heap-allocated, leak-resistant.
  • On drop or zeroize(), Vec<u8> and String secrets 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> uses zeroize::Zeroizing<T> for stack-allocated, auto-zeroing fixed-size secrets.
  • Dynamic<T> uses secrecy::SecretBox<T> for heap-allocated, leak-protected dynamic secrets.
  • Both forward ZeroizeOnDrop and Zeroize for 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

[dependencies]

secure-gate = "0.5.0"

With serde:

secure-gate = { version = "0.5.0", features = ["serde"] }

Quick Start

use secure_gate::{Fixed, Dynamic, secure, fixed_alias};

// Fixed-size key (stack when zeroize off)
fixed_alias!(Aes256Key, 32);
let key: Aes256Key = [0u8; 32].into();

assert_eq!(key.len(), 32);
key[0] = 1;  // DerefMut

// Dynamic password (heap, full protection)
let mut pw = Dynamic::<String>::new("hunter2".to_string());

assert_eq!(pw.len(), 7);
assert_eq!(&*pw, "hunter2");  // Deref

pw.push('!');
pw.finish_mut();  // shrink_to_fit

// Macros
let iv = secure!([u8; 16], [1u8; 16]);
assert_eq!(iv.0, [1u8; 16]);

// Extraction
let extracted = key.into_inner();
assert_eq!(extracted, [1u8; 32]);

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 secure_gate::fixed_alias;

// Crypto keys
fixed_alias!(Aes256Key, 32);
fixed_alias!(HmacSha256Key, 32);
fixed_alias!(X25519SecretKey, 32);

// Nonces and IVs
fixed_alias!(AesGcmIv12, 12);
fixed_alias!(AesCbcIv16, 16);
fixed_alias!(ChaCha20Nonce12, 12);
fixed_alias!(XChaCha20Nonce24, 24);

// Salts
fixed_alias!(Salt16, 16);

// Usage
let key: Aes256Key = [0u8; 32].into();
let iv = AesGcmIv12::new(rand::random::<[u8; 12]>());

Dynamic-Size (Heap-Optimized)

use secure_gate::dynamic_alias;

// Strings and passwords
dynamic_alias!(Password, String);
dynamic_alias!(JwtSecret, String);

// Byte vectors
dynamic_alias!(Token, Vec<u8>);
dynamic_alias!(Payload, Vec<u8>);

// Usage
let pw: Password = Dynamic::new("hunter2".to_string());
let token: Token = Dynamic::new_boxed(Box::new(vec![0u8; 32]));

assert_eq!(pw.len(), 7);
pw.push('!');  // DerefMut
assert_eq!(&*pw, "hunter2!");

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) or Dynamic<T> (dynamic).
  • ZeroizeMode / new_full_wipe → Removed; zeroize handles wiping.
  • SecurePasswordDynamic<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 = Dynamic::<String>::new("hunter2".to_string());
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.