Skip to main content

mockforge_foundation/
encryption_error.rs

1//! Error types and handling for encryption operations
2//!
3//! This module provides comprehensive error handling for all encryption-related
4//! operations, including encryption, decryption, key management, and validation.
5
6#![allow(missing_docs)]
7
8use std::fmt;
9use thiserror::Error;
10
11/// Errors that can occur during encryption/decryption operations
12#[derive(Error, Debug)]
13pub enum EncryptionError {
14    /// Invalid key length or format
15    #[error("Invalid key: {message}")]
16    InvalidKey { message: String },
17
18    /// Invalid nonce/IV length or format
19    #[error("Invalid nonce: {message}")]
20    InvalidNonce { message: String },
21
22    /// Authentication failed during decryption
23    #[error("Authentication failed: {message}")]
24    AuthenticationFailed { message: String },
25
26    /// Invalid ciphertext format
27    #[error("Invalid ciphertext: {message}")]
28    InvalidCiphertext { message: String },
29
30    /// Key derivation failed
31    #[error("Key derivation failed: {message}")]
32    KeyDerivationFailed { message: String },
33
34    /// Key not found in key store
35    #[error("Key not found: {key_id}")]
36    KeyNotFound { key_id: String },
37
38    /// Insufficient permissions for key operation
39    #[error("Access denied: {message}")]
40    AccessDenied { message: String },
41
42    /// Key store operation failed
43    #[error("Key store error: {message}")]
44    KeyStoreError { message: String },
45
46    /// Random number generation failed
47    #[error("Random generation failed: {message}")]
48    RandomGenerationFailed { message: String },
49
50    /// Invalid algorithm configuration
51    #[error("Invalid algorithm: {message}")]
52    InvalidAlgorithm { message: String },
53
54    /// Cipher operation failed
55    #[error("Cipher operation failed: {message}")]
56    CipherOperationFailed { message: String },
57
58    /// Base64 encoding/decoding failed
59    #[error("Base64 operation failed: {message}")]
60    Base64Error { message: String },
61
62    /// Serialization/deserialization failed
63    #[error("Serialization failed: {message}")]
64    SerializationError { message: String },
65
66    /// Template processing failed
67    #[error("Template processing failed: {message}")]
68    TemplateError { message: String },
69
70    /// Auto-encryption configuration error
71    #[error("Auto-encryption configuration error: {message}")]
72    AutoEncryptionConfigError { message: String },
73
74    /// Workspace encryption error
75    #[error("Workspace encryption error: {message}")]
76    Workspace { message: String },
77
78    /// Generic encryption error
79    #[error("Encryption error: {message}")]
80    Generic { message: String },
81}
82
83impl EncryptionError {
84    /// Create a new invalid key error
85    pub fn invalid_key(message: impl Into<String>) -> Self {
86        Self::InvalidKey {
87            message: message.into(),
88        }
89    }
90
91    /// Create a new invalid nonce error
92    pub fn invalid_nonce(message: impl Into<String>) -> Self {
93        Self::InvalidNonce {
94            message: message.into(),
95        }
96    }
97
98    /// Create a new authentication failed error
99    pub fn authentication_failed(message: impl Into<String>) -> Self {
100        Self::AuthenticationFailed {
101            message: message.into(),
102        }
103    }
104
105    /// Create a new invalid ciphertext error
106    pub fn invalid_ciphertext(message: impl Into<String>) -> Self {
107        Self::InvalidCiphertext {
108            message: message.into(),
109        }
110    }
111
112    /// Create a new key derivation failed error
113    pub fn key_derivation_failed(message: impl Into<String>) -> Self {
114        Self::KeyDerivationFailed {
115            message: message.into(),
116        }
117    }
118
119    /// Create a new key not found error
120    pub fn key_not_found(key_id: impl Into<String>) -> Self {
121        Self::KeyNotFound {
122            key_id: key_id.into(),
123        }
124    }
125
126    /// Create a new access denied error
127    pub fn access_denied(message: impl Into<String>) -> Self {
128        Self::AccessDenied {
129            message: message.into(),
130        }
131    }
132
133    /// Create a new key store error
134    pub fn key_store_error(message: impl Into<String>) -> Self {
135        Self::KeyStoreError {
136            message: message.into(),
137        }
138    }
139
140    /// Create a new random generation failed error
141    pub fn random_generation_failed(message: impl Into<String>) -> Self {
142        Self::RandomGenerationFailed {
143            message: message.into(),
144        }
145    }
146
147    /// Create a new invalid algorithm error
148    pub fn invalid_algorithm(message: impl Into<String>) -> Self {
149        Self::InvalidAlgorithm {
150            message: message.into(),
151        }
152    }
153
154    /// Create a new cipher operation failed error
155    pub fn cipher_operation_failed(message: impl Into<String>) -> Self {
156        Self::CipherOperationFailed {
157            message: message.into(),
158        }
159    }
160
161    /// Create a new base64 error
162    pub fn base64_error(message: impl Into<String>) -> Self {
163        Self::Base64Error {
164            message: message.into(),
165        }
166    }
167
168    /// Create a new serialization error
169    pub fn serialization_error(message: impl Into<String>) -> Self {
170        Self::SerializationError {
171            message: message.into(),
172        }
173    }
174
175    /// Create a new template error
176    pub fn template_error(message: impl Into<String>) -> Self {
177        Self::TemplateError {
178            message: message.into(),
179        }
180    }
181
182    /// Create a new auto-encryption config error
183    pub fn auto_encryption_config_error(message: impl Into<String>) -> Self {
184        Self::AutoEncryptionConfigError {
185            message: message.into(),
186        }
187    }
188
189    /// Create a new workspace encryption error
190    pub fn workspace_encryption_error(message: impl Into<String>) -> Self {
191        Self::Workspace {
192            message: message.into(),
193        }
194    }
195
196    /// Create a new generic error
197    pub fn generic(message: impl Into<String>) -> Self {
198        Self::Generic {
199            message: message.into(),
200        }
201    }
202
203    /// Check if this is a recoverable error
204    pub fn is_recoverable(&self) -> bool {
205        match self {
206            Self::InvalidKey { .. }
207            | Self::InvalidNonce { .. }
208            | Self::AuthenticationFailed { .. }
209            | Self::InvalidCiphertext { .. }
210            | Self::KeyNotFound { .. }
211            | Self::InvalidAlgorithm { .. }
212            | Self::Base64Error { .. }
213            | Self::SerializationError { .. }
214            | Self::TemplateError { .. }
215            | Self::AutoEncryptionConfigError { .. } => false,
216
217            Self::KeyDerivationFailed { .. }
218            | Self::AccessDenied { .. }
219            | Self::KeyStoreError { .. }
220            | Self::RandomGenerationFailed { .. }
221            | Self::CipherOperationFailed { .. }
222            | Self::Workspace { .. }
223            | Self::Generic { .. } => true,
224        }
225    }
226
227    /// Get error severity level
228    pub fn severity(&self) -> ErrorSeverity {
229        match self {
230            Self::AuthenticationFailed { .. } | Self::AccessDenied { .. } => {
231                ErrorSeverity::Critical
232            }
233
234            Self::InvalidKey { .. }
235            | Self::InvalidNonce { .. }
236            | Self::InvalidCiphertext { .. }
237            | Self::InvalidAlgorithm { .. } => ErrorSeverity::High,
238
239            Self::KeyDerivationFailed { .. }
240            | Self::KeyStoreError { .. }
241            | Self::RandomGenerationFailed { .. }
242            | Self::CipherOperationFailed { .. } => ErrorSeverity::Medium,
243
244            Self::Base64Error { .. }
245            | Self::SerializationError { .. }
246            | Self::TemplateError { .. }
247            | Self::AutoEncryptionConfigError { .. }
248            | Self::Workspace { .. }
249            | Self::Generic { .. } => ErrorSeverity::Low,
250
251            Self::KeyNotFound { .. } => ErrorSeverity::Info,
252        }
253    }
254}
255
256/// Error severity levels for encryption operations
257#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
258pub enum ErrorSeverity {
259    /// Informational messages (non-fatal)
260    Info,
261    /// Low severity errors (minor issues)
262    Low,
263    /// Medium severity errors (issues that should be addressed)
264    Medium,
265    /// High severity errors (significant problems)
266    High,
267    /// Critical severity errors (blocks operation)
268    Critical,
269}
270
271/// Result type alias for encryption operations
272pub type EncryptionResult<T> = Result<T, EncryptionError>;
273
274/// Error context for enhanced debugging and error reporting
275#[derive(Debug, Clone)]
276pub struct ErrorContext {
277    /// Name of the encryption operation that failed
278    pub operation: String,
279    /// Additional context information (key-value pairs)
280    pub context: HashMap<String, String>,
281    /// Timestamp when the error occurred
282    pub timestamp: chrono::DateTime<chrono::Utc>,
283}
284
285impl ErrorContext {
286    /// Create a new error context
287    pub fn new(operation: impl Into<String>) -> Self {
288        Self {
289            operation: operation.into(),
290            context: HashMap::new(),
291            timestamp: chrono::Utc::now(),
292        }
293    }
294
295    /// Add context information
296    pub fn with_context(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
297        self.context.insert(key.into(), value.into());
298        self
299    }
300}
301
302/// Enhanced encryption error with additional debugging context
303#[derive(Debug)]
304pub struct ContextualError {
305    /// The underlying encryption error that occurred
306    pub error: EncryptionError,
307    /// Additional context information for debugging
308    pub context: ErrorContext,
309}
310
311impl fmt::Display for ContextualError {
312    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313        write!(
314            f,
315            "Encryption error in {} at {}: {} (context: {:?})",
316            self.context.operation, self.context.timestamp, self.error, self.context.context
317        )
318    }
319}
320
321impl std::error::Error for ContextualError {
322    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
323        Some(&self.error)
324    }
325}
326
327/// Error recovery strategies for handling encryption failures
328#[derive(Debug, Clone)]
329pub enum ErrorRecoveryStrategy {
330    /// Retry with exponential backoff
331    RetryWithBackoff {
332        /// Maximum number of retry attempts
333        max_attempts: usize,
334        /// Base delay in milliseconds between retries
335        base_delay_ms: u64,
336    },
337    /// Use fallback encryption method (e.g., different algorithm)
338    FallbackMethod,
339    /// Skip encryption for this operation (data stored unencrypted)
340    SkipEncryption,
341    /// Request user intervention to resolve the error
342    ManualIntervention,
343    /// Fail fast and return error immediately (no retry)
344    FailFast,
345}
346
347impl EncryptionError {
348    /// Suggest recovery strategy based on error type
349    pub fn suggested_recovery(&self) -> ErrorRecoveryStrategy {
350        match self {
351            Self::RandomGenerationFailed { .. } => ErrorRecoveryStrategy::RetryWithBackoff {
352                max_attempts: 3,
353                base_delay_ms: 100,
354            },
355
356            Self::KeyStoreError { .. } | Self::KeyDerivationFailed { .. } => {
357                ErrorRecoveryStrategy::ManualIntervention
358            }
359
360            Self::AuthenticationFailed { .. } | Self::AccessDenied { .. } => {
361                ErrorRecoveryStrategy::FailFast
362            }
363
364            Self::InvalidKey { .. } | Self::InvalidNonce { .. } => {
365                ErrorRecoveryStrategy::FallbackMethod
366            }
367
368            _ => ErrorRecoveryStrategy::RetryWithBackoff {
369                max_attempts: 2,
370                base_delay_ms: 50,
371            },
372        }
373    }
374
375    /// Convert to contextual error
376    pub fn with_context(self, context: ErrorContext) -> ContextualError {
377        ContextualError {
378            error: self,
379            context,
380        }
381    }
382}
383
384use std::collections::HashMap;