shadow_crypt_shell/decryption/
workflow.rs

1use rayon::prelude::*;
2use shadow_crypt_core::{
3    algorithm::Algorithm,
4    memory::{SecureBytes, SecureKey, SecureString},
5    progress::ProgressCounter,
6    report::{DecryptionReport, KeyDerivationReport},
7    v1::{
8        crypt::decrypt_bytes,
9        file::{EncryptedFile, PlaintextFile},
10        header_ops::get_kdf_params,
11        key::KeyDerivationParams,
12        key_ops::derive_key,
13    },
14};
15
16use crate::{
17    decryption::{
18        file::{DecryptionInput, DecryptionInputFile, DecryptionOutputFile},
19        file_ops::{load_encrypted_file, store_plaintext_file},
20    },
21    errors::WorkflowResult,
22    ui::{display_decryption_report, display_progress},
23    utils::parse_string_from_bytes,
24};
25
26pub fn run_workflow(input: DecryptionInput) -> WorkflowResult<()> {
27    let counter = ProgressCounter::new(input.files.len() as u64);
28
29    // Process files in parallel using rayon
30    input
31        .files
32        .par_iter()
33        .map(|input_file| {
34            counter.increment();
35            display_progress(&counter);
36            process_file_decryption(input_file.to_owned(), &input.password, &input.output_dir)
37        })
38        .for_each(display_decryption_report);
39
40    Ok(())
41}
42
43fn process_file_decryption(
44    file: DecryptionInputFile,
45    password: &SecureString,
46    output_dir: &std::path::Path,
47) -> WorkflowResult<DecryptionReport> {
48    let start_time = std::time::Instant::now();
49
50    let input_file: DecryptionInputFile = file;
51
52    let encrypted_file: EncryptedFile = load_encrypted_file(&input_file)?;
53
54    let filename_nonce: &[u8; 24] = &encrypted_file.header().filename_nonce;
55    let filename_ciphertext: &[u8] = &encrypted_file.header().filename_ciphertext;
56
57    let content_nonce: &[u8; 24] = &encrypted_file.header().content_nonce;
58    let content_ciphertext: &[u8] = encrypted_file.ciphertext();
59
60    let salt: &[u8; 16] = &encrypted_file.header().salt;
61    let kdf_params: KeyDerivationParams = get_kdf_params(encrypted_file.header());
62    let (key, _kdf_report): (SecureKey, KeyDerivationReport) =
63        derive_key(password.as_str().as_bytes(), salt, &kdf_params)?;
64
65    let (filename_bytes, algorithm): (SecureBytes, Algorithm) =
66        decrypt_bytes(filename_ciphertext, key.as_bytes(), filename_nonce)?;
67
68    let filename: SecureString = parse_string_from_bytes(&filename_bytes)?;
69
70    let (content_bytes, _algorithm): (SecureBytes, Algorithm) =
71        decrypt_bytes(content_ciphertext, key.as_bytes(), content_nonce)?;
72
73    let plaintext_file = PlaintextFile::new(filename.clone(), content_bytes);
74    let output_file: DecryptionOutputFile = store_plaintext_file(&plaintext_file, output_dir)?;
75
76    let duration = start_time.elapsed();
77
78    Ok(DecryptionReport::new(
79        input_file.filename,
80        output_file.filename,
81        duration,
82        algorithm,
83    ))
84}