pub mod at_rest;
pub mod envelope;
pub mod in_transit;
pub mod key_management;
pub use at_rest::{AtRestEncryptor, FieldEncryptor};
pub use envelope::EnvelopeEncryptor;
pub use in_transit::TlsConfigBuilder;
pub use key_management::KeyManager;
use crate::error::{Result, SecurityError};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum EncryptionAlgorithm {
#[default]
Aes256Gcm,
ChaCha20Poly1305,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EncryptionMetadata {
pub algorithm: EncryptionAlgorithm,
pub key_id: String,
pub iv: Vec<u8>,
pub aad: Option<Vec<u8>>,
pub encrypted_at: chrono::DateTime<chrono::Utc>,
}
impl EncryptionMetadata {
pub fn new(
algorithm: EncryptionAlgorithm,
key_id: String,
iv: Vec<u8>,
aad: Option<Vec<u8>>,
) -> Self {
Self {
algorithm,
key_id,
iv,
aad,
encrypted_at: chrono::Utc::now(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EncryptedData {
pub ciphertext: Vec<u8>,
pub metadata: EncryptionMetadata,
}
impl EncryptedData {
pub fn new(ciphertext: Vec<u8>, metadata: EncryptionMetadata) -> Self {
Self {
ciphertext,
metadata,
}
}
pub fn to_json_bytes(&self) -> Result<Vec<u8>> {
serde_json::to_vec(self).map_err(SecurityError::from)
}
pub fn from_json_bytes(bytes: &[u8]) -> Result<Self> {
serde_json::from_slice(bytes).map_err(SecurityError::from)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
pub enum KeyDerivationFunction {
Pbkdf2Sha256,
#[default]
Argon2id,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KeyDerivationParams {
pub kdf: KeyDerivationFunction,
pub salt: Vec<u8>,
pub iterations: Option<u32>,
pub memory_cost: Option<u32>,
pub time_cost: Option<u32>,
pub parallelism: Option<u32>,
}
impl KeyDerivationParams {
pub fn pbkdf2_recommended(salt: Vec<u8>) -> Self {
Self {
kdf: KeyDerivationFunction::Pbkdf2Sha256,
salt,
iterations: Some(600000), memory_cost: None,
time_cost: None,
parallelism: None,
}
}
pub fn argon2_recommended(salt: Vec<u8>) -> Self {
Self {
kdf: KeyDerivationFunction::Argon2id,
salt,
iterations: None,
memory_cost: Some(19456), time_cost: Some(2),
parallelism: Some(1),
}
}
}
pub fn derive_key(
password: &[u8],
params: &KeyDerivationParams,
key_length: usize,
) -> Result<Vec<u8>> {
match params.kdf {
KeyDerivationFunction::Pbkdf2Sha256 => {
let iterations = params
.iterations
.ok_or_else(|| SecurityError::key_derivation("iterations required for PBKDF2"))?;
use ring::pbkdf2;
let mut key = vec![0u8; key_length];
pbkdf2::derive(
pbkdf2::PBKDF2_HMAC_SHA256,
std::num::NonZeroU32::new(iterations)
.ok_or_else(|| SecurityError::key_derivation("invalid iterations"))?,
¶ms.salt,
password,
&mut key,
);
Ok(key)
}
KeyDerivationFunction::Argon2id => {
use argon2::{Algorithm, Argon2, Params, Version};
let memory_cost = params
.memory_cost
.ok_or_else(|| SecurityError::key_derivation("memory_cost required for Argon2"))?;
let time_cost = params
.time_cost
.ok_or_else(|| SecurityError::key_derivation("time_cost required for Argon2"))?;
let parallelism = params
.parallelism
.ok_or_else(|| SecurityError::key_derivation("parallelism required for Argon2"))?;
let argon2_params = Params::new(memory_cost, time_cost, parallelism, Some(key_length))
.map_err(|e| {
SecurityError::key_derivation(format!("invalid Argon2 params: {}", e))
})?;
let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, argon2_params);
let mut key = vec![0u8; key_length];
argon2
.hash_password_into(password, ¶ms.salt, &mut key)
.map_err(|e| SecurityError::key_derivation(format!("Argon2 error: {}", e)))?;
Ok(key)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_key_derivation_pbkdf2() {
let password = b"test_password";
let salt = b"test_salt_12345678";
let params = KeyDerivationParams::pbkdf2_recommended(salt.to_vec());
let key = derive_key(password, ¶ms, 32).expect("key derivation failed");
assert_eq!(key.len(), 32);
let key2 = derive_key(password, ¶ms, 32).expect("key derivation failed");
assert_eq!(key, key2);
let key3 = derive_key(b"different", ¶ms, 32).expect("key derivation failed");
assert_ne!(key, key3);
}
#[test]
fn test_key_derivation_argon2() {
let password = b"test_password";
let salt = b"test_salt_12345678";
let params = KeyDerivationParams::argon2_recommended(salt.to_vec());
let key = derive_key(password, ¶ms, 32).expect("key derivation failed");
assert_eq!(key.len(), 32);
let key2 = derive_key(password, ¶ms, 32).expect("key derivation failed");
assert_eq!(key, key2);
}
#[test]
fn test_encryption_metadata_serialization() {
let metadata = EncryptionMetadata::new(
EncryptionAlgorithm::Aes256Gcm,
"key-001".to_string(),
vec![1, 2, 3, 4, 5],
Some(vec![6, 7, 8]),
);
let json = serde_json::to_string(&metadata).expect("serialization failed");
let deserialized: EncryptionMetadata =
serde_json::from_str(&json).expect("deserialization failed");
assert_eq!(deserialized.algorithm, metadata.algorithm);
assert_eq!(deserialized.key_id, metadata.key_id);
assert_eq!(deserialized.iv, metadata.iv);
assert_eq!(deserialized.aad, metadata.aad);
}
}