| Crates.io | saferet |
| lib.rs | saferet |
| version | 0.1.0 |
| created_at | 2025-11-18 04:39:07.650527+00 |
| updated_at | 2025-11-18 04:39:07.650527+00 |
| description | Secure types for handling sensitive data in Rust with automatic memory cleanup and protection against accidental exposure |
| homepage | |
| repository | https://github.com/lambdalisue/rs-saferet |
| max_upload_size | |
| id | 1937895 |
| size | 26,762 |
Secure types for handling sensitive data in Rust
Provides SecretString and SecretBytes for safely managing passwords, API keys, cryptographic keys, and other sensitive information with automatic memory cleanup and protection against accidental exposure.
zeroize to clear sensitive data from memory on Drop*** instead of actual valuesexpose() methoduse saferet::{SecretString, SecretBytes};
// SecretString for text-based secrets
let api_key = SecretString::new("sk_live_abc123");
println!("{:?}", api_key); // Output: SecretString(***)
// Access the actual value when needed
let header = format!("Bearer {}", api_key.expose());
// SecretBytes for binary secrets
let crypto_key = SecretBytes::new(vec![0x01, 0x02, 0x03, 0x04]);
println!("{:?}", crypto_key); // Output: SecretBytes(***)
// Constant-time comparison (enabled by default)
let password1 = SecretString::new("secret");
let password2 = SecretString::new("secret");
assert_eq!(password1, password2); // Uses constant-time comparison
Add to your Cargo.toml:
[dependencies]
saferet = "0.1"
| Feature | Description | Default |
|---|---|---|
constant-time-eq |
Timing-attack resistant comparison using subtle |
β Enabled |
serde |
Serialize/Deserialize support | β Enabled |
Minimal configuration (zeroize only):
[dependencies]
saferet = { version = "0.1", default-features = false }
Custom features:
[dependencies]
# Only constant-time comparison, no serde
saferet = { version = "0.1", default-features = false, features = ["constant-time-eq"] }
# Only serde support, no constant-time comparison
saferet = { version = "0.1", default-features = false, features = ["serde"] }
For text-based sensitive data like passwords, API keys, and authentication tokens.
use saferet::SecretString;
let password = SecretString::new("my-secret-password");
// Masked in logs and error messages
println!("{}", password); // Output: ***
println!("{:?}", password); // Output: SecretString(***)
// Explicit access when needed
if password.expose() == "my-secret-password" {
// Use password.expose() carefully
}
// Works with various string types
let from_string: SecretString = String::from("key").into();
let from_str: SecretString = "key".into();
let parsed: SecretString = "key".parse().unwrap();
For binary sensitive data like cryptographic keys, hashes, and binary tokens.
use saferet::SecretBytes;
let key = SecretBytes::new(vec![0x01, 0x02, 0x03, 0x04]);
// Masked in logs and error messages
println!("{}", key); // Output: ***
println!("{:?}", key); // Output: SecretBytes(***)
// Explicit access when needed
let key_slice: &[u8] = key.expose();
// or using AsRef
let key_slice: &[u8] = key.as_ref();
// Works with various byte types
let from_vec: SecretBytes = vec![0x01, 0x02].into();
let from_slice: SecretBytes = [0x03, 0x04].as_ref().into();
constant-time-eq feature)expose() methodexpose() and log/print the result, the value will be exposedBest practices:
expose()expose() results in logs, error messages, or debug outputconstant-time-eq feature for cryptographic comparisonsWith the serde feature (enabled by default), both types support serialization:
use saferet::SecretString;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct Config {
#[serde(default)]
api_key: SecretString,
}
// Serialization includes the actual value
// β οΈ Be careful when serializing to logs or untrusted destinations
let config = Config {
api_key: SecretString::new("secret-key"),
};
let json = serde_json::to_string(&config).unwrap();
// json contains the actual "secret-key" value
Security note: Serialization bypasses the masking protection. Only serialize when absolutely necessary and ensure the destination is secure.
constant-time-eq feature (default)Uses constant-time comparison via the subtle crate to prevent timing attacks:
let secret1 = SecretString::new("password");
let secret2 = SecretString::new("password");
let secret3 = SecretString::new("different");
assert_eq!(secret1, secret2); // Constant-time comparison
assert_ne!(secret1, secret3); // Constant-time comparison
constant-time-eq featureUses standard PartialEq implementation (faster but potentially vulnerable to timing attacks):
[dependencies]
saferet = { version = "0.1", default-features = false }
See the examples/ directory:
cargo run --example basic_usage
Run all tests with all feature combinations:
# All features (default)
cargo test
# No features
cargo test --no-default-features
# Individual features
cargo test --no-default-features --features serde
cargo test --no-default-features --features constant-time-eq
| Crate | Zeroize | Masked Display | Constant-time Eq | Type Safety |
|---|---|---|---|---|
saferet |
β | β | β (optional) | String + Bytes |
secrecy |
β | β | β | Generic |
zeroize |
β | β | β | Generic |
subtle |
β | β | β | Primitives |
saferet combines the best features in an easy-to-use package specifically designed for string and byte secrets.
Licensed under MIT license (LICENSE or http://opensource.org/licenses/MIT).
Contributions are welcome! Please feel free to submit a Pull Request.