Update src/main.rs: Added some error handling

This commit is contained in:
2023-01-29 23:55:08 +05:30
parent 777aca0360
commit 8d1c739802

View File

@@ -5,85 +5,206 @@
// Copyright (C) 2023 Arkaprabha Chakraborty // Copyright (C) 2023 Arkaprabha Chakraborty
use orion::{aead, kdf}; use orion::{aead, kdf};
use passterm; use passterm::read_password;
use std::env::args; use std::env::args;
use std::fs::read_to_string; use std::fs::read_to_string;
use std::fs::File; use std::fs::File;
use std::io::{stdout, Read, Write}; use std::io::{stdout, Read, Write};
use std::process::exit;
const PROGRAM_NAME: &str = "rustcm-cli"; const PROGRAM_NAME: &str = "rustcm-cli";
const PROGRAM_VERSION: &str = "0.1.0-alpha"; const PROGRAM_VERSION: &str = "0.1.0-alpha";
pub fn get_password(prompt: &str) -> String { pub fn get_password(prompt: &str) -> String {
print!("{}", prompt); print!("{}", prompt);
stdout().flush().unwrap(); match stdout().flush() {
let password: String = passterm::read_password().unwrap(); Ok(_) => (),
Err(_) => {
eprintln!("Error: Could not flush stdout");
exit(0);
}
};
let password: String = match read_password() {
Ok(temp) => temp,
Err(_) => {
eprintln!("Error: Could not read the password");
exit(0)
}
};
println!(); println!();
password password
} }
pub fn encrypt(plaintext: String, secret_key: orion::kdf::SecretKey) -> Vec<u8> { pub fn encrypt(plaintext: String, secret_key: orion::kdf::SecretKey) -> Vec<u8> {
let plaintext = plaintext.into_bytes(); let plaintext = plaintext.into_bytes();
let ciphertext: Vec<u8> = let ciphertext: Vec<u8> = match aead::seal(&secret_key, &plaintext) {
aead::seal(&secret_key, &plaintext).expect("Error: Could not encrypt the data"); Ok(temp) => temp,
Err(_) => {
eprintln!("Error: Could not encrypt the data");
exit(0);
}
};
ciphertext ciphertext
} }
pub fn get_secret_key(presalt: [u8; 32], password: String) -> orion::kdf::SecretKey { pub fn get_secret_key(salt_bytes: [u8; 32], password: String) -> orion::kdf::SecretKey {
let password = kdf::Password::from_slice(password.as_bytes()).unwrap(); let password = match kdf::Password::from_slice(password.as_bytes()) {
let salt = kdf::Salt::from_slice(&presalt).unwrap(); Ok(temp) => temp,
let secret_key = Err(_) => {
kdf::derive_key(&password, &salt, 3, 8, 32).expect("Error: Could not create secret key"); eprintln!("Error: Could not generate the password");
exit(0)
}
};
let salt = match kdf::Salt::from_slice(&salt_bytes) {
Ok(temp) => temp,
Err(_) => {
eprintln!("Error: Could not generate the salt");
exit(0)
}
};
let secret_key = match kdf::derive_key(&password, &salt, 3, 8, 32) {
Ok(temp) => temp,
Err(_) => {
eprintln!("Error: Could not generate the secret key");
exit(0)
}
};
secret_key secret_key
} }
pub fn get_presalt() -> [u8; 32] { pub fn get_salt_bytes() -> [u8; 32] {
let mut presalt = [0u8; 32]; let mut salt_bytes = [0u8; 32];
orion::util::secure_rand_bytes(&mut presalt).expect("Error: Could not get presalt"); match orion::util::secure_rand_bytes(&mut salt_bytes) {
Ok(temp) => temp,
Err(_) => {
eprintln!("Error: Could not generate the salt");
exit(0)
}
};
presalt salt_bytes
} }
pub fn get_salt(presalt: [u8; 32]) -> orion::kdf::Salt { pub fn get_salt(salt_bytes: [u8; 32]) -> orion::kdf::Salt {
let salt = kdf::Salt::from_slice(&presalt).expect("Error: Could not create salt"); let salt = match kdf::Salt::from_slice(&salt_bytes) {
Ok(temp) => temp,
Err(_) => {
eprintln!("Error: Could not generate the salt");
exit(0)
}
};
salt salt
} }
pub fn write_plain(path: String, plaintext: String) { pub fn write_plain(path: String, plaintext: String) {
let mut file = File::create(path).expect("Error: Could not create the file"); let mut file = match File::create(path) {
file.write(&plaintext.into_bytes()) Ok(temp) => temp,
.expect("Error: Could not write_cipher plaintext to the file"); Err(_) => {
file.flush().unwrap(); eprintln!("Error: Could not create the file");
exit(0);
}
};
match file.write(&plaintext.into_bytes()) {
Ok(_) => (),
Err(_) => {
eprintln!("Error: Could not write the data to the file");
exit(0);
}
};
match file.flush() {
Ok(_) => (),
Err(_) => {
eprintln!("Error: Could not flush the file");
exit(0);
}
};
} }
pub fn write_cipher(path: String, presalt: [u8; 32], ciphertext: Vec<u8>) { pub fn write_cipher(path: String, salt_bytes: [u8; 32], ciphertext: Vec<u8>) {
let mut file = File::create(path).expect("Error: Could not create the file"); let mut file = match File::create(path) {
file.write(&presalt).unwrap(); Ok(temp) => temp,
file.write(&ciphertext) Err(_) => {
.expect("Error: Could not write_cipher presalt to the file"); eprintln!("Error: Could not create the file");
file.flush().unwrap(); exit(0);
}
};
match file.write(&salt_bytes) {
Ok(temp) => temp,
Err(_) => {
eprintln!("Error: Could write the salt_bytes to the file");
exit(0);
}
};
match file.write(&ciphertext) {
Ok(temp) => temp,
Err(_) => {
eprintln!("Error: Could not write the ciphertext to the file");
exit(0);
}
};
match file.flush() {
Ok(temp) => temp,
Err(_) => {
eprintln!("Error: Could not flush the file");
exit(0);
}
};
} }
pub fn read_plain(path: String) -> String { pub fn read_plain(path: String) -> String {
read_to_string(path).unwrap() let file_str: String = match read_to_string(path) {
Ok(temp) => temp,
Err(_) => {
eprintln!("Error: Could not read the file");
exit(0);
}
};
file_str
} }
pub fn read_cipher(path: String) -> (Vec<u8>, Vec<u8>) { pub fn read_cipher(path: String) -> (Vec<u8>, Vec<u8>) {
let mut file = File::open(path).expect("Error: Could not open the file"); let mut file = match File::open(path) {
let metadata = File::metadata(&file).expect("Error: Could not read the metadata off the file"); Ok(temp) => temp,
let mut data: Vec<u8> = vec![0u8; metadata.len() as usize]; Err(_) => {
file.read(&mut data) eprintln!("Error: Could not open the file");
.expect("Error: Could not read from the file"); exit(0);
}
};
let mut presalt: Vec<u8> = vec![0u8; 32]; let metadata = match File::metadata(&file) {
presalt.clone_from_slice(&data[..32]); Ok(temp) => temp,
Err(_) => {
eprintln!("Error: Could not read the metadata off the file");
exit(0);
}
};
let mut data: Vec<u8> = vec![0u8; metadata.len() as usize];
match file.read(&mut data) {
Ok(_) => (),
Err(_) => {
eprintln!("Error: Could not read the file");
exit(0);
}
};
let mut salt_bytes: Vec<u8> = vec![0u8; 32];
salt_bytes.clone_from_slice(&data[..32]);
let mut cypher: Vec<u8> = vec![0u8; (metadata.len() - 32) as usize]; let mut cypher: Vec<u8> = vec![0u8; (metadata.len() - 32) as usize];
cypher.clone_from_slice(&data[32..]); cypher.clone_from_slice(&data[32..]);
(presalt, cypher) (salt_bytes, cypher)
} }
pub fn decrypt(ciphertext: Vec<u8>, secret_key: orion::kdf::SecretKey) -> String { pub fn decrypt(ciphertext: Vec<u8>, secret_key: orion::kdf::SecretKey) -> String {
@@ -104,11 +225,14 @@ where
let slice = v.as_slice(); let slice = v.as_slice();
let array: [T; 32] = match slice.try_into() { let array: [T; 32] = match slice.try_into() {
Ok(bytes) => bytes, Ok(bytes) => bytes,
Err(_) => panic!( Err(_) => {
"Error: Expected a Vec of length {} but it was {}", eprintln!(
"Error: Expected a vector of length {} but it was {}",
32, 32,
v.len() v.len()
), );
exit(0);
}
}; };
array array
@@ -117,11 +241,18 @@ where
fn main() { fn main() {
let mut args = args(); let mut args = args();
while args.next() != None { while args.next() != None {
let arg_str = args.next().unwrap(); let arg_str: String = match args.next() {
if arg_str.eq("--help") || arg_str.eq("-h") { Some(temp) => temp,
None => {
exit(0);
}
};
match arg_str.as_str() {
"--help" | "-h" => {
println!( println!(
"{PROGRAM_NAME} {PROGRAM_VERSION} "{PROGRAM_NAME} {PROGRAM_VERSION}
Rust Simple Text Cipher Machine. Encrypts or decrypts files using the ChaCha20-Poly1305 algorithm. Rust Simple Text Cipher Machine.
USAGE: USAGE:
rustcm-cli [COMMAND] rustcm-cli [COMMAND]
@@ -138,36 +269,77 @@ COMMAND:
-d, --decrypt <input-path> <output-path> -d, --decrypt <input-path> <output-path>
Runs the program in decryption mode." Runs the program in decryption mode."
); )
} else if arg_str.eq("--version") || arg_str.eq("-v") { }
"--version" | "-v" => {
println!( println!(
"rustcm-cli (0.1.0) "rustcm-cli (0.1.0-alpha)
Copyright (C) 2023 Arkaprabha Chakraborty Copyright (C) 2023 Arkaprabha Chakraborty
License GPLv3: GNU GPL version 3 License GPLv3: GNU GPL version 3
This is free software: you are free to change and redistribute it. This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. There is NO WARRANTY, to the extent permitted by law.
Written by Arkaprabha Chakraborty" Written by Arkaprabha Chakraborty"
) );
} }
if arg_str.eq("--encrypt") || arg_str.eq("-e") { "encrypt" | "-e" => {
let path: String = match args.next() {
Some(temp) => temp,
None => {
eprintln!("Error: Was expecting two arguments but received none");
exit(0);
}
};
let output: String = match args.next() {
Some(temp) => temp,
None => {
eprintln!("Error: Was expecting two arguments but received one");
exit(0);
}
};
let password: String = get_password("Password: "); let password: String = get_password("Password: ");
let path: String = args.next().unwrap(); let plaintext: String = read_plain(path);
let output: String = args.next().unwrap(); let salt_bytes = get_salt_bytes();
let plaintext: String = read_plain(path.clone()); let secret_key = get_secret_key(salt_bytes, password);
let presalt = get_presalt();
let secret_key = get_secret_key(presalt, password.clone());
let ciphertext = encrypt(plaintext, secret_key); let ciphertext = encrypt(plaintext, secret_key);
write_cipher(output, presalt, ciphertext);
} else if arg_str.eq("--decrypt") || arg_str.eq("-d") { write_cipher(output, salt_bytes, ciphertext);
let password: String = get_password("Password: ");
let path: String = args.next().unwrap(); println!("File encrypted successfully")
let output: String = args.next().unwrap();
let (presalt, ciphertext) = read_cipher(path.clone());
let presalt: [u8; 32] = convert_to_array(presalt);
let secret_key = get_secret_key(presalt, password);
let plaintext = decrypt(ciphertext, secret_key);
write_plain(output, plaintext);
} }
"--decrypt" | "-d" => {
let path: String = match args.next() {
Some(temp) => temp,
None => {
eprintln!("Error: Was expecting two arguments but received none");
exit(0);
}
};
let output: String = match args.next() {
Some(temp) => temp,
None => {
eprintln!("Error: Was expecting two arguments but received one");
exit(0);
}
};
let password: String = get_password("Password: ");
let (salt_bytes, ciphertext) = read_cipher(path);
let salt_bytes: [u8; 32] = convert_to_array(salt_bytes);
let secret_key = get_secret_key(salt_bytes, password);
let plaintext = decrypt(ciphertext, secret_key);
write_plain(output, plaintext);
println!("File decryption was successful")
}
_ => {
eprintln!("Error: Unrecognized argument");
}
};
} }
} }