shadow_crypt_shell/encryption/
workflow.rs

1use rayon::prelude::*;
2use shadow_crypt_core::{
3    algorithm::Algorithm,
4    memory::SecureKey,
5    progress::ProgressCounter,
6    report::{EncryptionReport, KeyDerivationReport},
7    v1::{
8        crypt::encrypt_bytes,
9        file::{EncryptedFile, PlaintextFile},
10        header::FileHeader,
11        key::KeyDerivationParams,
12        key_ops::derive_key,
13    },
14};
15
16use crate::{
17    encryption::{
18        file::{EncryptionInput, EncryptionInputFile, EncryptionOutputFile},
19        file_ops::{load_plaintext_file, store_encrypted_file},
20        nonce::generate_nonce,
21        salt::generate_salt,
22    },
23    errors::WorkflowResult,
24    ui::{display_encryption_report, display_key_derivation_report, display_progress},
25};
26
27pub fn run_workflow(input: EncryptionInput) -> WorkflowResult<()> {
28    let salt: [u8; 16] = generate_salt()?;
29
30    let params = KeyDerivationParams::from(input.security_profile);
31    let (key, report): (SecureKey, KeyDerivationReport) =
32        derive_key(input.password.as_str().as_bytes(), salt.as_ref(), &params)?;
33
34    display_key_derivation_report(&report);
35
36    let counter = ProgressCounter::new(input.files.len() as u64);
37
38    // Process files in parallel using rayon
39    input
40        .files
41        .par_iter()
42        .map(|input_file| {
43            counter.increment();
44            display_progress(&counter);
45            process_file_encryption(
46                input_file.to_owned(),
47                &key,
48                &salt,
49                &params,
50                &input.output_dir,
51            )
52        })
53        .for_each(display_encryption_report);
54
55    Ok(())
56}
57
58fn process_file_encryption(
59    file: EncryptionInputFile,
60    key: &SecureKey,
61    salt: &[u8; 16],
62    kdf_params: &KeyDerivationParams,
63    output_dir: &std::path::Path,
64) -> WorkflowResult<EncryptionReport> {
65    let start_time = std::time::Instant::now();
66
67    let input_file: EncryptionInputFile = file;
68
69    let filename_nonce: [u8; 24] = generate_nonce()?;
70    let content_nonce: [u8; 24] = generate_nonce()?;
71    let plaintext_file: PlaintextFile = load_plaintext_file(&input_file)?;
72
73    let (filename_ciphertext, _): (Vec<u8>, Algorithm) = encrypt_bytes(
74        input_file.filename.as_bytes(),
75        key.as_bytes(),
76        &filename_nonce,
77    )?;
78
79    let (content_ciphertext, algorithm): (Vec<u8>, Algorithm) = encrypt_bytes(
80        plaintext_file.content().as_slice(),
81        key.as_bytes(),
82        &content_nonce,
83    )?;
84
85    let header = FileHeader::new(
86        *salt,
87        kdf_params.clone(),
88        content_nonce,
89        filename_nonce,
90        filename_ciphertext,
91    );
92
93    let encrypted_file = EncryptedFile::new(header, content_ciphertext);
94
95    let output_file: EncryptionOutputFile = store_encrypted_file(&encrypted_file, output_dir)?;
96
97    let duration = start_time.elapsed();
98
99    Ok(EncryptionReport::new(
100        input_file.filename,
101        output_file.filename,
102        duration,
103        algorithm,
104    ))
105}