encryptify-lib 1.0.4

A library for encrypting and decrypting files and folders using AES-256 bit encryption.
Documentation
use aes::Aes256;
use block_modes::{block_padding::Pkcs7, BlockMode, Cbc};
use std::{
    fs::{self, File},
    io::Write,
};

use crate::zipper::zip_folder;

type Aes256Cbc = Cbc<Aes256, Pkcs7>;

/// Encrypts a file using AES-256 encryption.
///
/// # Arguments
///
/// * `file_path` - Path of the file to encrypt.
/// * `key` - The encryption key. (32 bytes)
///
/// # Panics
///
/// This function will panic if:
/// - The file cannot be read.
/// - The output file cannot be created.
/// - The encrypted data cannot be written to the output file.
///
pub fn encrypt_file(file_path: &str, key: &[u8]) {
    let file_content = fs::read(file_path).expect("Failed to read the file");

    let iv = [0u8; 16]; // Initialization vector

    let cipher = Aes256Cbc::new_from_slices(key, &iv).expect("Failed to create AES cipher");

    let cipher_text = cipher.encrypt_vec(&file_content);

    let mut output_file =
        File::create(format!("{}.encrypted", file_path)).expect("Failed to create the output file");

    output_file
        .write_all(&cipher_text)
        .expect("Failed to write encrypted data to the output file");
}

/// Decrypts an AES-256 encrypted file.
///
/// # Arguments
///
/// * `file_path` - Path of the file to decrypt.
/// * `key` - The encryption key. (32 bytes)
///
/// # Panics
///
/// This function will panic if:
/// - The file cannot be read.
/// - The cipher cannot be created.
/// - The output file cannot be created.
/// - The decrypted data cannot be written to the output file.
pub fn decrypt_file(file_path: &str, key: &[u8]) {
    let encrypted_content = fs::read(file_path).expect("Failed to read the encrypted file");

    let iv = [0u8; 16];

    let cipher = Aes256Cbc::new_from_slices(key, &iv).expect("Failed to create AES cipher");

    let decrypted_content = cipher
        .decrypt_vec(&encrypted_content)
        .expect("Failed to decrypt data");

    let mut output_file =
        File::create(format!("{}.decrypted", file_path)).expect("Failed to create the output file");

    output_file
        .write_all(&decrypted_content)
        .expect("Failed to write decrypted data to the output file");
}

pub fn encrypt_folder(folder_path: &str, key: &[u8]) {
    let zip_path = format!("{}.zip", folder_path);
    zip_folder(folder_path, &zip_path);
    encrypt_file(&zip_path, key);
    fs::remove_file(&zip_path).expect("Failed to remove the intermediate zip file :|");
}

pub fn decrypt_folder(file_path: &str, key: &[u8]) {
    decrypt_file(file_path, key);

    let zip_path = format!("{}.decrypted", file_path); // As the decrypt file function appends .decrypted to the file name

    let zip_file = File::open(&zip_path).expect("Failed to open the decrypted zip file");

    let mut archive = zip::ZipArchive::new(zip_file).expect("Failed to read the Zip archive");

    let output_folder = file_path.trim_end_matches(".zip.encrypted");

    fs::create_dir(output_folder).expect("Failed to create the output folder");

    for i in 0..archive.len() {
        let mut file = archive
            .by_index(i)
            .expect("Failed to get the file from the archive");

        let output_file_path = format!("{}/{}", output_folder, file.name()); // TODO: Fix security flaw here, needs sanitization

        let mut output_file =
            File::create(output_file_path).expect("Failed to create the output file");

        std::io::copy(&mut file, &mut output_file)
            .expect("Failed to copy contents to extracted file.");
    }

    fs::remove_file(&zip_path).expect("Failed to delete the intermediate 'decrypted' zip file");
}