From edacd660fe022a757dba72d0e51fa8ff3dabd485 Mon Sep 17 00:00:00 2001 From: Pablu23 <43807157+Pablu23@users.noreply.github.com> Date: Thu, 2 Feb 2023 22:02:23 +0100 Subject: [PATCH] Initial commit --- .gitignore | 2 + Cargo.lock | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 13 +++ src/main.rs | 258 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 522 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..206dfb3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target/* +.vscode diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..f287b61 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,249 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "blake2b_simd" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72936ee4afc7f8f736d1c38383b56480b5497b4617b4a77bdbf1d2ababc76127" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chacha20" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fc89c7c5b9e7a02dfe45cd2367bae382f9ed31c61ca8debe5f827c420a2f08" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "cipher" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "cpufeatures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "folder_encryptor" +version = "0.1.0" +dependencies = [ + "chacha20", + "rand", + "rand_core", + "rpassword", + "rust-argon2", +] + +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "libc" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rpassword" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +dependencies = [ + "libc", + "rtoolbox", + "winapi", +] + +[[package]] +name = "rtoolbox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "034e22c514f5c0cb8a10ff341b9b048b5ceb21591f31c8f44c43b960f9b3524a" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "rust-argon2" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50162d19404029c1ceca6f6980fe40d45c8b369f6f44446fa14bb39573b5bb9" +dependencies = [ + "base64", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..9323e0d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "folder_encryptor" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +chacha20 = "0.9.0" +rand = "0.8.5" +rand_core = "0.6.4" +rpassword = "7.2.0" +rust-argon2 = "1.0.0" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..8ca55b0 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,258 @@ +use chacha20::cipher::{KeyIvInit, StreamCipher}; +use chacha20::XChaCha20; +use rand::RngCore; +use rand_core::OsRng; +use std::path::Path; +use std::{ + env, + fs, + fs::File, + io, + io::{Read, Write}, + // time::SystemTime, +}; + +extern crate rpassword; + +use rpassword::read_password; + +const BUFFER_LEN: usize = 50 * 1024 * 1024; // 50 MiB + +fn encrypt_file( + source_path: String, + dest_path: String, + nonce: &[u8; 24], + key: &Vec, +) -> io::Result<()> { + let mut cipher = XChaCha20::new(key[..32].as_ref().into(), nonce.into()); + + let source_file = Path::new(&source_path); + + if !source_file.try_exists()? { + return Err(io::Error::from(io::ErrorKind::NotFound)); + } + + let file_name = source_file.file_name().unwrap_or_default(); + let path = dest_path + "/" + file_name.to_str().unwrap_or_default() + ".cha"; + + if Path::new(&path).try_exists()? { + fs::remove_file(&path)?; + } + + let mut source_file = File::open(source_path)?; + let mut dest_file = File::create(path)?; + + // Stack allocated buffer + // let mut buffer = [0u8; BUFFER_LEN]; + + // Heap allocated buffer (Allows larger sized buffer, up to 50 % max ram) + let mut buffer = vec![0u8; BUFFER_LEN].into_boxed_slice(); + + dest_file.write(nonce)?; + + loop { + let read_count = source_file.read(&mut buffer).unwrap(); + + if read_count == BUFFER_LEN { + cipher.apply_keystream(&mut buffer); + dest_file.write(&buffer).unwrap(); + } else { + cipher.apply_keystream(&mut buffer[..read_count]); + dest_file.write(&buffer[..read_count]).unwrap(); + break; + } + } + + return Ok(()); +} + +fn decrypt_file(source_path: String, pwd: &String, config: &argon2::Config) -> io::Result<()> { + let mut nonce = [0u8; 24]; + + let path_info = Path::new(&source_path); + + if !path_info.try_exists()? { + return Err(io::Error::from(io::ErrorKind::NotFound)); + } + + let path = &source_path[..&source_path.len() - 4]; + + if Path::new(&path).exists() { + fs::remove_file(&path)?; + } + + let mut source_file = File::open(&source_path)?; + let mut dest_file = File::create(path)?; + + source_file.read(&mut nonce)?; + + let key = argon2::hash_raw(pwd.as_bytes(), &nonce, &config).unwrap(); + + let mut cipher = XChaCha20::new(key[..32].as_ref().into(), &nonce.into()); + + // Stack allocated buffer + // let mut buffer = [0u8; BUFFER_LEN]; + + // Heap allocated buffer (Allows larger sized buffer, up to 50 % max ram) + let mut buffer = vec![0u8; BUFFER_LEN].into_boxed_slice(); + + loop { + let read_count = source_file.read(&mut buffer).unwrap(); + + if read_count == BUFFER_LEN { + cipher.apply_keystream(&mut buffer); + dest_file.write(&buffer).unwrap(); + } else { + cipher.apply_keystream(&mut buffer[..read_count]); + dest_file.write(&buffer[..read_count]).unwrap(); + break; + } + } + + return Ok(()); +} + +fn main() -> io::Result<()> { + let config = argon2::Config { + variant: argon2::Variant::Argon2id, + hash_length: 32, + lanes: 8, + mem_cost: 16 * 1024, + time_cost: 8, + ..Default::default() + }; + + let exe = env::current_exe().unwrap(); + let cwd = env::current_dir().unwrap(); + let private = cwd.join("private"); + + if private.exists() { + let paths = fs::read_dir(&private).unwrap(); + + print!("Type password for encrypted files: "); + std::io::stdout().flush().unwrap(); + let pwd = read_password().unwrap(); + + for path_result in paths { + let path = path_result.unwrap().path(); + + if path.is_file() { + decrypt_file(String::from(path.to_str().unwrap()), &pwd, &config)?; + fs::remove_file(String::from(path.to_str().unwrap()))?; + } + } + + //fs::remove_dir_all(private).unwrap(); + } else { + let paths = fs::read_dir(&cwd).unwrap(); + + for path_result in paths { + let path = path_result.unwrap().path(); + + if path.is_file() && path != exe { + println!("{path:?}"); + } + } + + println!("Encrypt files? [y]es / [n]o"); + + let input: u8 = std::io::stdin().bytes().next().unwrap().unwrap(); + + match input { + b'n' => return Ok(()), + b'y' => (), + _ => panic!("Input was not correct!"), + } + + fs::create_dir(&private).unwrap(); + + print!("Type password to encrypt files: "); + std::io::stdout().flush().unwrap(); + let pwd = read_password().unwrap(); + + let mut nonce = [0u8; 24]; + OsRng.fill_bytes(&mut nonce); + + let key = argon2::hash_raw(pwd.as_bytes(), &nonce, &config).unwrap(); + + let paths = fs::read_dir(cwd).unwrap(); + + for path_result in paths { + let path = path_result.unwrap().path(); + + if path.is_file() && path != exe { + encrypt_file( + String::from(path.to_str().unwrap()), + String::from(private.to_str().unwrap()), + &nonce, + &key, + ) + .unwrap(); + } + } + } + + // let start = SystemTime::now(); + + // let source_path = String::from("E:\\Programieren\\Rust\\folder_encryptor\\1gb.test.bin.cha"); + // // let plaintext: String = String::from("Das ist ein Test string"); + // let pwd: String = String::from("TestPassword!"); + + // // let mut nonce = [0u8; 24]; + // // OsRng.fill_bytes(&mut nonce); + + // // let key = argon2::hash_raw(pwd.as_bytes(), &nonce, &config).unwrap(); + + // decrypt_file(source_path, &pwd, &config)?; + + // let encrypt_time = start.elapsed().unwrap(); + + // println!("Encrypt took {encrypt_time:?}"); + + Ok(()) + + // let start = SystemTime::now(); + + // Decrypt Part + //dist_file.seek(SeekFrom::Start(0)).unwrap(); + // drop(dist_file); + + // cipher.seek(0u32); + + // let mut dist_file = File::open(dist_path).unwrap(); + // let decrypted_path = source_path.clone() + ".decrypted.bin"; + // let mut decrypted_file = File::create(decrypted_path).unwrap(); + + // let mut read_nonce = [0u8; 24]; + + // let nonce_size = dist_file.read(&mut read_nonce).unwrap(); + + // assert_eq!(24, nonce_size); + // assert_eq!(read_nonce, nonce); + + // let t = dist_file.stream_position().unwrap(); + + // println!("{t}"); + + // let mut decrypt_buffer = [0u8; BUFFER_LEN]; + + // loop { + // let read_count = dist_file.read(&mut decrypt_buffer).unwrap(); + + // println!("Decrypt Read: {read_count}"); + + // if read_count == BUFFER_LEN { + // cipher.apply_keystream(&mut decrypt_buffer); + // decrypted_file.write(&decrypt_buffer).unwrap(); + // } else { + // cipher.apply_keystream(&mut decrypt_buffer[..read_count]); + // decrypted_file.write(&decrypt_buffer[..read_count]).unwrap(); + // break; + // } + // } + + // let decrypt_time = start.elapsed().unwrap(); + + // println!("Encrypt took {encrypt_time:?}"); + // println!("Decrypt took {decrypt_time:?}"); +}