# cryptainer
**Small, password-based authenticated encryption for Rust.**
Encrypt byte slices or Serde-compatible structs with **Argon2id** and
**AES-256-GCM**, then decrypt them with a simple, typed API. `cryptainer` is
`no_std`-friendly and keeps file I/O optional.
[](https://crates.io/crates/cryptainer)
[](https://docs.rs/cryptainer)
[](LICENSE)
## Features
- Password-based encryption with Argon2id
- AES-256-GCM authenticated encryption
- `no_std` support with `alloc`
- Optional derived-key zeroization
- Optional file helpers through `std`
- Optional bincode-backed struct encryption through `derive`
## Quick start
Add the crate with its standard-library defaults:
```toml
[dependencies]
cryptainer = "2.1"
```
### Encrypt bytes
```rust
use cryptainer::{decrypt_data, encrypt_data};
let mut rng = rand::rng();
let encrypted = encrypt_data("correct horse battery staple", b"hello world", &mut rng)?;
let plaintext = decrypt_data(&encrypted, "correct horse battery staple")?;
```
`encrypt_data` returns a `CryptData` value containing the salt, nonce, and
ciphertext. Keep it together until you are ready to persist it or decrypt it.
### Encrypt structs
Enable the `derive` feature:
```toml
[dependencies]
cryptainer = { version = "2.1", features = ["derive"] }
serde = { version = "1", features = ["derive"] }
```
Then derive `Cryptainer` alongside Serde:
```rust
use cryptainer::Cryptainer;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Cryptainer)]
struct Secret {
message: String,
}
let mut rng = rand::rng();
let secret = Secret { message: "hello world".into() };
let encrypted = secret.encrypt("password", &mut rng)?;
let decrypted = Secret::decrypt(&encrypted, "password")?;
```
The derive generates `encrypt` and `decrypt` methods. Serialization uses
bincode 2; encrypted data is still authenticated by AES-GCM.
### Save and load files
```rust
use cryptainer::{decrypt_file, encrypt_data, save_file};
let mut rng = rand::rng();
let encrypted = encrypt_data("password", b"secret", &mut rng)?;
save_file("secret.stuff", &encrypted)?;
let plaintext = decrypt_file("secret.stuff", "password")?;
```
## Format and security
Encrypted output is stored as:
`salt (16 bytes) || nonce (12 bytes) || ciphertext`
The ciphertext includes the AES-GCM authentication tag. Passwords are processed
with Argon2id to derive a 256-bit encryption key. A fresh salt and nonce are
generated for every call to `encrypt_data`; callers must provide a
cryptographically secure RNG.
When enabled, the `zeroize` feature clears derived keys and temporary
serialization buffers when they are dropped. It cannot clear passwords,
caller-owned plaintext, decrypted return values, or encrypted data retained
for persistence.
`cryptainer` does not provide password storage, password strength checking, key
rotation, or secure password transport. Applications should handle those
concerns separately.
## API at a glance
- `encrypt_data(password, plaintext, rng) -> Result<CryptData, CryptError>`
- `decrypt_data(data, password) -> Result<Vec<u8>, CryptError>`
- `decrypt_bytes(data, password) -> Result<Vec<u8>, CryptError>`
- `encrypt_value(value, password, rng) -> Result<CryptData, CryptError>` *(with `derive`)*
- `decrypt_value(data, password) -> Result<T, CryptError>` *(with `derive`)*
- `save_file(file_path, data) -> Result<(), CryptError>` *(std only)*
- `decrypt_file(file_path, password) -> Result<Vec<u8>, CryptError>` *(std only)*
## Features
- `std` (default): enables file I/O and standard library integration
- `zeroize` (default): zeroizes derived keys and temporary serialized plaintext
buffers where supported
- `derive`: enables bincode-backed struct encryption and the `Cryptainer` derive
## License
MIT