Skip to content

Slurp9187/secure-gate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

72 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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 that forwards to the inner type.
  • When the zeroize feature is enabled, FixedZeroizing<T> and DynamicZeroizing<T> provide automatic zeroing on drop.

Installation

[dependencies]
secure-gate = "0.5.5"

With automatic zeroing (recommended for most use cases):

secure-gate = { version = "0.5.5", features = ["zeroize"] }

Features

Feature Description
zeroize Enables zeroize integration (Zeroizing, SecretBox)
serde Optional serialization support
alloc Required for Dynamic<T> (enabled by default)
std Not required – works in no_std environments

Quick Start

use secure_gate::{secure, fixed_alias, dynamic_alias};

// Type aliases
fixed_alias!(Aes256Key, 32);
fixed_alias!(Nonce12, 12);
dynamic_alias!(Password, String);

// Construction — idiomatic and zero-cost
let key = Aes256Key::from(rng.gen());           // explicit
let key2: Aes256Key = rng.gen().into();         // natural .into()
let key3 = Aes256Key::new(rng.gen());           // classic

let nonce = Nonce12::from(rng.gen());
let nonce2: Nonce12 = rng.gen().into();

// Access the secret — loud, clear, and zero-cost
let key_bytes: &[u8] = key.expose_secret();
let key_bytes_mut: &mut [u8] = key.expose_secret_mut();
key_bytes_mut[0] = 0xFF;                         // e.g. key scheduling, HKDF, etc.
assert_eq!(key[0], 0xFF);

// Heap-based secrets
let mut password: Password = secure!(String, "hunter2".to_string());
password.push('!');
password.finish_mut(); // shrink_to_fit() on String/Vec<u8>

// Access the secret directly
let pw_str: &str = password.expose_secret();
let pw_str_mut: &mut str = password.expose_secret_mut().as_mut_str();
pw_str_mut.push('!');

// Auto-zeroing variants (requires `zeroize` feature)
let temp_key = secure_gate::secure_zeroizing!([u8; 32], derive_key());
let secret_vec = secure_gate::secure_zeroizing!(heap Vec<u8>, Box::new(secret_bytes));

Memory Guarantees (zeroize feature enabled)

Type Allocation Auto-zero on drop Full capacity wiped Slack memory eliminated Notes
Fixed<T> Stack Yes (via Zeroizing) Yes Yes (no heap) No allocation
Dynamic<T> Heap Yes (via SecretBox) 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
  • All zeroing uses zeroize::Zeroize (volatile writes + compiler fence).
  • Vec<u8> and String have their full current capacity zeroed and are truncated to length zero.
  • The underlying allocation is freed on drop (standard Rust behavior); capacity is not forcibly reduced unless finish_mut() / shrink_to_fit() is called.
  • Past reallocations may leave copies of data elsewhere in memory. Pre-allocate with the final expected size to avoid reallocations.

Important: DynamicZeroizing<T> (i.e. SecretBox<T>) is accessed via .expose_secret() and .expose_secret_mut() — it does not implement Deref.

Macros

secure!([u8; 32], rng.gen())                    // Fixed<[u8; 32]>
secure!(String, "pw".into())                    // Dynamic<String>
secure!(Vec<u8>, data.to_vec())                 // Dynamic<Vec<u8>>

secure_zeroizing!([u8; 32], key)                // FixedZeroizing<[u8; 32]> (zeroize feature)
secure_zeroizing!(heap Vec<u8>, Box::new(data)) // DynamicZeroizing<Vec<u8>>

fixed_alias!(MyKey, 32)
dynamic_alias!(MySecret, Vec<u8>)

Example Aliases

fixed_alias!(Aes128Key, 16);
fixed_alias!(Aes256Key, 32);
fixed_alias!(XChaCha20Nonce, 24);
dynamic_alias!(Password, String);
dynamic_alias!(JwtSigningKey, Vec<u8>);

// Usage
let key = Aes256Key::from(rng.gen());
let key2: Aes256Key = rng.gen().into();

Zero-cost — proven on real hardware

Implementation Median time Max overhead vs raw
raw [u8; 32] ~460 ps
Fixed<[u8; 32]> ~460 ps +28 ps (0.000000028 s)
fixed_alias!(Key, 32) ~475 ps +13 ps

Test machine (2019-era laptop):
Lenovo ThinkPad L13 (81XH) • Intel Core i7-10510U (4c/8t @ 1.80 GHz) • 16 GB RAM • Windows 10 Pro 26100.1
Measured with Criterion 0.5 under real-world load (including Windows Update check).

Even under background load, overhead is < 0.1 CPU cycles — indistinguishable from raw arrays.

View full interactive report

Migration from v0.4.x

  • SecureGate<T>Fixed<T> (stack) or Dynamic<T> (heap)
  • .expose_secret()value.expose_secret() (returns &T)
  • .expose_secret_mut()value.expose_secret_mut() (returns &mut T)
  • Automatic zeroing → FixedZeroizing<T> or DynamicZeroizing<T> (with zeroize feature)

Note: .view() and .view_mut() are deprecated in v0.5.5 and will be removed in v0.6.0.

Changelog

See CHANGELOG.md

License

MIT OR Apache-2.0

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published