Expand description
§Vitamin C Encrypt
Secure, flexible and fast encryption for Rust types.
This crate is part of the Vitamin C framework to make cryptography code healthy.
§Features
- Type-safe encryption: Encrypt and decrypt Rust types with compile-time safety
- AES-256-GCM: Uses AES-256-GCM authenticated encryption via AWS-LC
- 256-bit keys only: Enforces quantum-resistant key sizes for future security
- Protected types integration: Works seamlessly with
vitaminc-protectedfor sensitive data handling - Additional Authenticated Data (AAD): Support for authenticated but unencrypted data
- Automatic nonce generation: Secure random nonce generation for each encryption operation
§Installation
Add this to your Cargo.toml:
[dependencies]
vitaminc-encrypt = "0.1.0-pre4"
vitaminc-random = "0.1.0-pre4" # For key generation§Quick Start
use vitaminc_encrypt::Key;
use vitaminc_random::{SafeRand, SeedableRng, Generatable};
// Generate a key
let mut rng = SafeRand::from_entropy();
let key = Key::random(&mut rng).expect("Failed to generate key");
// Encrypt a message
let ciphertext = vitaminc_encrypt::encrypt(&key, "secret message").expect("Failed to encrypt");
// Decrypt it back
let plaintext: String = vitaminc_encrypt::decrypt(&key, ciphertext).expect("Failed to decrypt");
assert_eq!(plaintext, "secret message");§Usage
§Key Management
The Key type represents a 256-bit encryption key. Vitamin C only supports 256-bit keys to ensure quantum security and compatibility with AWS-LC.
§Generating a Key
use vitaminc_encrypt::Key;
use vitaminc_random::{SafeRand, SeedableRng, Generatable};
let mut rng = SafeRand::from_entropy();
let key = Key::random(&mut rng).expect("Failed to generate key");§Creating a Key from Bytes
use vitaminc_encrypt::Key;
let key_bytes = [0u8; 32]; // In practice, use securely generated bytes
let key = Key::from(key_bytes);§Encrypting Data
The encrypt function can encrypt any type that implements the Encrypt trait. Built-in support includes:
String&strVec<u8>[u8; N](fixed-size byte arrays)Protected<T>whereTimplementsEncrypt
use vitaminc_encrypt::{encrypt, Key};
use vitaminc_random::{SafeRand, SeedableRng, Generatable};
let key = Key::random(&mut SafeRand::from_entropy()).expect("Failed to generate key");
// Encrypt a string
let ciphertext = encrypt(&key, "secret message").expect("encryption failed");
// Encrypt bytes
let data = vec![1, 2, 3, 4, 5];
let ciphertext = encrypt(&key, data).expect("encryption failed");
// Encrypt a fixed-size array
let array = [0u8; 32];
let ciphertext = encrypt(&key, array).expect("encryption failed");§Decrypting Data
The decrypt function requires you to specify the expected type:
// Decrypt to String
let ciphertext = encrypt(&key, "secret message").expect("encryption failed");
let plaintext: String = decrypt(&key, ciphertext).expect("decryption failed");
// Decrypt to Vec<u8>
let ciphertext = encrypt(&key, vec![1, 2, 3, 4, 5]).expect("encryption failed");
let bytes: Vec<u8> = decrypt(&key, ciphertext).expect("decryption failed");
// Decrypt to fixed-size array
let ciphertext = encrypt(&key, [0u8; 32]).expect("encryption failed");
let array: [u8; 32] = decrypt(&key, ciphertext).expect("decryption failed");§Additional Authenticated Data (AAD)
AAD allows you to authenticate additional context alongside the ciphertext without encrypting it. This is useful for binding metadata to encrypted data.
use vitaminc_encrypt::{encrypt_with_aad, decrypt_with_aad, Key};
let key = Key::from([0u8; 32]);
// Encrypt with context
let user_id = "user_123";
let ciphertext = encrypt_with_aad(&key, "secret message", user_id).expect("encryption failed");
// Decrypt with the same context
let plaintext: String = decrypt_with_aad(&key, ciphertext, user_id).expect("decryption failed");
assert_eq!(plaintext, "secret message");§AAD Must Match
Decryption will fail if the AAD doesn’t match:
use vitaminc_encrypt::{encrypt_with_aad, decrypt_with_aad};
// Encrypt with one context
let ciphertext = encrypt_with_aad(&key, "secret", "context_1").expect("encryption failed");
// Try to decrypt with different context - this will fail!
let result: Result<String, _> = decrypt_with_aad(&key, ciphertext, "context_2");
assert!(result.is_err());§Working with Protected Types
Vitamin C Encrypt integrates with vitaminc-protected to ensure sensitive data is handled securely:
use vitaminc_protected::Protected;
use vitaminc_encrypt::{encrypt, decrypt, Key};
use vitaminc_random::{SafeRand, SeedableRng, Generatable};
let key = Key::random(&mut SafeRand::from_entropy()).expect("Failed to generate key");
// Encrypt protected data
let sensitive = Protected::new("password123".to_string());
let ciphertext = encrypt(&key, sensitive).expect("encryption failed");
// Decrypt back to protected data
let decrypted: Protected<String> = decrypt(&key, ciphertext).expect("decryption failed");§Encrypting Keys (Key Wrapping)
Keys can be encrypted with other keys, enabling key hierarchy and key wrapping:
use vitaminc_encrypt::{Key, encrypt, decrypt};
use vitaminc_random::{SafeRand, SeedableRng, Generatable};
let mut rng = SafeRand::from_entropy();
// Generate a key encryption key (KEK)
let kek = Key::random(&mut rng).expect("key generation failed");
// Generate a data encryption key (DEK)
let dek = Key::random(&mut rng).expect("key generation failed");
// Wrap the DEK with the KEK
let wrapped_dek = encrypt(&kek, dek).expect("encryption failed");
// Later, unwrap the DEK
let unwrapped_dek: Key = decrypt(&kek, wrapped_dek).expect("decryption failed");§Convenience Functions vs Traits
This crate provides both convenience functions and traits:
Convenience functions (recommended for most use cases):
encrypt- Encrypt with no AADencrypt_with_aad- Encrypt with AADdecrypt- Decrypt with no AADdecrypt_with_aad- Decrypt with AAD
Traits (for custom implementations):
Encrypt- Implement to make your types encryptableDecrypt- Implement to make your types decryptableCipher- Implement to create custom cipher algorithms
Example using traits directly:
use vitaminc_encrypt::{Encrypt, Decrypt, Aes256Cipher, Key};
let key = Key::from([0u8; 32]);
let cipher = Aes256Cipher::new(&key).expect("cipher creation failed");
let ciphertext = "secret".encrypt(&cipher).expect("encryption failed");
let plaintext: String = String::decrypt(ciphertext, &cipher).expect("decryption failed");§Custom Encryptable Types
You can implement Encrypt and Decrypt for your own types to enable selective field encryption:
use vitaminc_encrypt::{Encrypt, Decrypt, Cipher, IntoAad, Unspecified, LocalCipherText};
struct User {
id: u64,
email: String,
ssn: String,
}
struct EncryptedUser {
id: u64,
email: String,
ssn: LocalCipherText, // Only encrypt the SSN
}
impl Encrypt for User {
type Encrypted = EncryptedUser;
fn encrypt_with_aad<'a, C, A>(
self,
cipher: &C,
aad: A,
) -> Result<Self::Encrypted, Unspecified>
where
C: Cipher,
A: IntoAad<'a>,
{
Ok(EncryptedUser {
id: self.id,
email: self.email,
ssn: self.ssn.encrypt_with_aad(cipher, aad).expect("encryption failed"),
})
}
}
impl Decrypt for User {
type Encrypted = EncryptedUser;
fn decrypt_with_aad<'a, C, A>(
encrypted: Self::Encrypted,
cipher: &C,
aad: A,
) -> Result<Self, Unspecified>
where
C: Cipher,
A: IntoAad<'a>,
{
Ok(User {
id: encrypted.id,
email: encrypted.email,
ssn: String::decrypt_with_aad(encrypted.ssn, cipher, aad).expect("decryption failed"),
})
}
}§Security Features
§AES-256-GCM
This crate uses AES-256-GCM (Galois/Counter Mode) which provides:
- Confidentiality: Data is encrypted with AES-256
- Authenticity: Built-in authentication prevents tampering
- Performance: Hardware-accelerated on most modern CPUs
§AWS-LC
Encryption is powered by AWS-LC, a FIPS-validated cryptographic library maintained by Amazon Web Services.
§256-bit Keys Only
Vitamin C enforces 256-bit keys to ensure:
- Resistance to quantum computer attacks (via AES-256)
- Compatibility with AWS-LC’s recommended parameters
- No risk of accidentally using weaker key sizes
§Automatic Nonce Generation
Each encryption operation generates a unique random nonce, preventing nonce reuse which could compromise security.
§Unspecified Errors
Encryption and decryption operations return an Unspecified error type that reveals no information about failures. This prevents side-channel attacks that could leak information through error messages.
§Best Practices
- Generate keys securely: Always use
Key::random()with a cryptographically secure RNG - Protect keys in memory: The
Keytype usesProtectedinternally to zeroize keys when dropped - Use AAD for context: Include relevant context (user ID, record ID, etc.) as AAD to prevent ciphertext substitution
- Never reuse keys across environments: Use different keys for development, staging, and production
- Rotate keys regularly: Implement key rotation policies for long-lived systems
- Store keys securely: Use key management systems (KMS) for production deployments
§Performance
Vitamin C Encrypt is designed for both security and performance:
- Zero-copy operations where possible
- Hardware acceleration via AWS-LC’s AES-NI support
- Minimal allocations during encryption/decryption
§Error Handling
All encryption operations return Result<T, Unspecified> where Unspecified is an opaque error type that reveals no details about the failure. This is intentional to prevent side-channel attacks.
use vitaminc_encrypt::{Key, encrypt, Unspecified};
use vitaminc_random::{SafeRand, SeedableRng, Generatable};
let key = Key::random(&mut SafeRand::from_entropy()).expect("Failed to generate key");
match encrypt(&key, "message") {
Ok(ciphertext) => println!("Encrypted successfully"),
Err(Unspecified) => eprintln!("Encryption failed"),
}§CipherStash
Vitamin C is brought to you by the team at CipherStash.
License: MIT
Structs§
- Aad
- Aes256
Cipher - Implements the AES-256-GCM cipher using the
aws-lc-rslibrary. - Encrypted
Key - Key
- 256-bit key type for use with symmetric encryption algorithms like AES-256-GCM. Vitaminc does not support smaller key sizes to ensure quantum security and compatibility with AWS-LC.
- Local
Cipher Text - Nonce
- Represents a nonce used in AEAD encryption of
Nbytes length. - Unspecified
- An error that provides no information about the failure. It is crucial when returning an error from a cipher operation that does not reveal any details about the failure as this can lead to side channel attacks.
Traits§
Functions§
- decrypt
- Decrypt the given ciphertext using the provided key.
Any type that implements the
Decrypttrait can be used so long as the value was encrypted with the same key. - decrypt_
with_ aad - Decrypt the given ciphertext using the provided key and additional authenticated data (AAD).
This is the reversed operation of
encrypt_with_aad. - encrypt
- Encrypt the given plaintext using the provided key.
Any type that implements the
Encrypttrait can be used. - encrypt_
with_ aad - Encrypt the given plaintext using the provided key and additional authenticated data (AAD).