trelent_hyok/
lib.rs

1//! Hold Your Own Key (HYOK) encryption service.
2//!
3//! This library provides a flexible system for managing encrypted data using
4//! customer-managed encryption keys. It supports:
5//!
6//! - Multiple key management services (AWS KMS, Azure Key Vault)
7//! - Custom encryption strategies
8//! - Key caching and persistence
9//! - Type-safe data handling
10//!
11//! The library follows the envelope encryption pattern where data is encrypted
12//! with Data Encryption Keys (DEKs) which are themselves protected by
13//! Customer Managed Keys (CMKs).
14
15pub mod cache;
16pub mod cmk;
17pub mod dek;
18pub mod error;
19mod held_data;
20mod builder;
21pub use builder::*;
22
23pub use held_data::*;
24
25use crate::dek::generator::DEKGenerator;
26use crate::dek::persistence::DEKPersistService;
27use crate::dek::scope::WithScope;
28use crate::dek::DEK;
29use crate::encryption::EncryptionStrategy;
30use crate::error::encryption::EncryptionError;
31use crate::error::generator::PersistError;
32use futures_util::TryFutureExt;
33use std::sync::Arc;
34
35/// Main service for managing encrypted data using the HYOK pattern.
36///
37/// This service coordinates:
38/// - Data Encryption Key (DEK) generation
39/// - Key persistence and caching
40/// - Encryption/decryption operations
41/// - Scope-based key management
42///
43/// # Type Parameters
44///
45/// * `S` - The encryption strategy used for data protection
46///
47/// # Example
48/// ```no_run
49/// use hyokashi::{HYOKServiceBuilder, EncryptionStrategy};
50///
51///
52///     let service = HYOKServiceBuilder::new()
53///         .with_fixed_length_generator(32)
54///         .with_aws_cmk(kms_client, "alias/my-key", algorithm)
55///         .with_aws_persistence(secrets_client)
56///         .build(encryption_strategy)?;
57///
58///     // Encrypt some data
59///     let held = service.hold_value(data, "my-scope".into(), metadata).await?;
60///
61///     // Decrypt the data
62///     let plain = service.release_value(held, "my-scope".into(), metadata).await?;
63///
64/// ```
65pub struct HYOKService<S: EncryptionStrategy> {
66    pub(crate) persist_service: Arc<DEKPersistService>,
67    pub(crate) generator: DEKGenerator,
68    pub(crate) strategy: S,
69}
70
71impl<S: EncryptionStrategy<EncryptionData = ED> + Send + Sync, ED: Send> HYOKService<S> {
72    /// Creates a new HYOK service instance.
73    ///
74    /// # Arguments
75    ///
76    /// * `persist_service` - Service for key persistence and caching
77    /// * `generator` - Strategy for generating new DEKs
78    /// * `strategy` - Strategy for encrypting/decrypting data
79    pub fn new(
80        persist_service: Arc<DEKPersistService>,
81        generator: DEKGenerator,
82        strategy: S
83    ) -> Self {
84        Self {
85            persist_service,
86            generator,
87            strategy,
88        }
89    }
90
91    /// Decrypts an object using its scope to locate the appropriate DEK.
92    ///
93    /// # Arguments
94    ///
95    /// * `obj` - The encrypted object to decrypt
96    ///
97    /// # Type Parameters
98    ///
99    /// * `T` - The encrypted object type
100    /// * `C` - The decrypted object type
101    ///
102    /// # Errors
103    ///
104    /// Returns an `EncryptionError` if:
105    /// - DEK retrieval fails
106    /// - Decryption fails
107    /// - Type conversion fails
108    pub async fn release_object<T, C>(&self, obj: &T) -> Result<C, EncryptionError>
109        where T: ReleaseHeldObject<C, S> + WithScope
110    {
111        let scope = obj.get_scope();
112        let dek = self
113            .prep_dek(scope)
114            .map_err(|e|
115                EncryptionError::new(format!("Could not prep DEK, Error: {:?}", e))
116            ).await?;
117        let result = obj.release_object(dek.into(), &self.strategy).await;
118        result
119    }
120
121    /// Decrypts a held value using the provided scope and metadata.
122    ///
123    /// # Arguments
124    ///
125    /// * `val` - The encrypted value to decrypt
126    /// * `scope` - The scope identifier for locating the DEK
127    /// * `encryption_data` - Additional metadata needed for decryption
128    ///
129    /// # Errors
130    ///
131    /// Returns an `EncryptionError` if:
132    /// - DEK retrieval fails
133    /// - Decryption fails
134    pub async fn release_value(
135        &self,
136        val: HeldValue,
137        scope: String,
138        encryption_data: ED
139    ) -> Result<Vec<u8>, EncryptionError> {
140        let dek = self
141            .prep_dek(scope)
142            .map_err(|e|
143                EncryptionError::new(format!("Could not prep DEK, Error: {:?}", e))
144            ).await?;
145        let result = val.release(dek.into(), &self.strategy, encryption_data).await;
146        result
147    }
148
149    /// Encrypts data using a DEK associated with the provided scope.
150    ///
151    /// # Arguments
152    ///
153    /// * `val` - The data to encrypt
154    /// * `scope` - The scope identifier for key management
155    /// * `encryption_data` - Additional metadata needed for encryption
156    ///
157    /// # Errors
158    ///
159    /// Returns an `EncryptionError` if:
160    /// - DEK retrieval or generation fails
161    /// - Encryption fails
162    pub async fn hold_value(
163        &self,
164        val: Vec<u8>,
165        scope: String,
166        encryption_data: ED
167    ) -> Result<HeldValue, EncryptionError> {
168        let dek = self
169            .prep_dek(scope)
170            .map_err(|e|
171                EncryptionError::new(format!("Could not prep DEK, Error: {:?}", e))
172            ).await?;
173        Held(val, dek.into(), &self.strategy, encryption_data).await
174    }
175
176    /// Retrieves or generates a DEK for the specified scope.
177    ///
178    /// # Arguments
179    ///
180    /// * `scope` - The scope identifier for the DEK
181    ///
182    /// # Returns
183    ///
184    /// The DEK associated with the scope, generating and persisting
185    /// a new one if none exists.
186    ///
187    /// # Errors
188    ///
189    /// Returns a `PersistError` if:
190    /// - Key retrieval fails
191    /// - Key generation fails
192    /// - Key persistence fails
193    pub async fn prep_dek(&self, scope: String) -> Result<DEK, PersistError> {
194        let fetch_result = self.persist_service.fetch_dek(scope.clone()).await;
195        let final_result = match fetch_result {
196            Ok(dek) => Ok(dek.into()),
197            _ => {
198                let dek = self.generator
199                    .new_dek()
200                    .map_err(|e|
201                        PersistError::Error(format!("Could not generate key, Error: {:?}", e))
202                    )?;
203                self.persist_service.save_dek(scope.clone(), dek.clone()).await?;
204                Ok(dek.into())
205            }
206        };
207        final_result
208    }
209}