diff --git a/Cargo.toml b/Cargo.toml index 568555e..c3da4cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,9 @@ name = "ruo" version = "0.1.0" edition = "2018" authors = ["Asjid Kalam "] +description = "Tiny hash cracked written in rust." +repository = "https://github.com/Asjidkalam/ruo.git" +license = "MIT" [dependencies] instant = "0.1.9" diff --git a/README.md b/README.md new file mode 100644 index 0000000..711db8d --- /dev/null +++ b/README.md @@ -0,0 +1,66 @@ +# `Ruo` 🧁 +Ruo is a dictionary-based password cracker written in rust 🦀. The primary purpose is to crack weak hashes/commonly used passwords. + +Cracked passwords will be printed to the terminal and saved in the file `$HOME/hashes.saved`. The `$HOME/hashes.saved` file is also used to not load password hashes that you already cracked when you run ruo the next time. + +

+ version +

+ + +## Available algorithms + + +| Name | Algorithm | Crates.io | +|-------------|------------|-----------| +| `md5` | MD5 | [![crates.io](https://img.shields.io/crates/v/md5.svg)](https://crates.io/crates/md5) | +| `sha1` | SHA-1 | [![crates.io](https://img.shields.io/crates/v/sha1.svg)](https://crates.io/crates/sha-1) | +| `sha256` | SHA-2 256 | [![crates.io](https://img.shields.io/crates/v/sha256.svg)](https://crates.io/crates/sha2) | +| `sha512` | SHA-2 512 | [![crates.io](https://img.shields.io/crates/v/sha256.svg)](https://crates.io/crates/sha2) | +|`ripemd320` | RIPEMD320 | [![crates.io](https://img.shields.io/crates/v/ripemd320.svg)](https://crates.io/crates/ripemd320)| + + +## Build From Source + +### Prerequisites + +You'll need the following tools to build from source: + +* [Rust](https://www.rust-lang.org/en-US/install.html) +* `Cargo` + + +### Building + +Clone the repository and use cargo to generate a release build. +```sh +$ git clone https://github.com/Asjidkalam/ruo.git +$ cd ruo/ +$ cargo build --release +``` + +## Usage +```sh +$ ./target/release/ruo +``` + +### Example +``` +🔫 ruo v0.1 +Loaded SHA-256 hash. +Loaded the wordlist file in 1838 millisecs. +🤍 Cracked! 244f28ce3685167745ad3a7f1760fd4483bbbb3fd150b9087b95442d4d6fd905 -> "PASSWORD1" in 6 millisecs +``` + +## Contribute + +* Suggest a feature / Report a bug +* More algorithms +* Better optimization +* Help me document the code :) + +## License +This project is licensed under the terms of the MIT license. +Check the [LICENSE](LICENSE.md) file out for license rights and limitations. + +🍰 \ No newline at end of file diff --git a/src/banner.rs b/src/banner.rs index 555024f..5310a4c 100644 --- a/src/banner.rs +++ b/src/banner.rs @@ -1,3 +1,3 @@ pub fn display_banner() { - println!("ruo (debug build)"); + println!("🔫 ruo v0.1"); } diff --git a/src/main.rs b/src/main.rs index 4e4dac6..35c0520 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use rayon::prelude::*; use serde::{Deserialize, Serialize}; use std::env; use std::fs; +use std::io::prelude::*; use std::io::ErrorKind; use std::path::Path; use std::process; @@ -19,8 +20,10 @@ lazy_static! { /* ruo currently supports: MD5, SHA1, RipeMD320, SHA256 and SHA512 + @odinshell - 01/08/2021 */ +// debug static mut LOAD_TIME: u128 = 0; #[derive(Serialize, Deserialize)] @@ -29,10 +32,25 @@ struct LocalHash { plaintext: String, } +fn load_local_hive() -> Vec { + let json_file_path = Path::new(&*LOCAL_HASH_PATH); + + let data = fs::read_to_string(json_file_path).unwrap(); + let mut local_hive: Vec = Vec::new(); + if fs::metadata(json_file_path).unwrap().len() != 0 { + local_hive = serde_json::from_str(&data).unwrap(); + } + local_hive +} + fn crack(line: String, hash_len: usize, now: std::time::Instant) { let formatted_hash: String = algorithms::create_hash(&line, hash_len); if formatted_hash == *HASH_INPUT { + /* + LOAD_TIME and unsafe{} is currently used for wordlist load time debug + will be removed later. + */ unsafe { println!( "🤍 Cracked! {} -> \"{}\" in {} millisecs", @@ -42,16 +60,26 @@ fn crack(line: String, hash_len: usize, now: std::time::Instant) { ); } - // save the hash locally - let mut local_hive: Vec = Vec::new(); + // loading the hash file, adding the new hash and saving locally. + let mut local_hive = load_local_hive(); + let new_hash = LocalHash { hash: formatted_hash, plaintext: line, }; + local_hive.push(new_hash); let json = serde_json::to_string(&local_hive).unwrap(); - fs::write(&*LOCAL_HASH_PATH, &json).expect("Unable to write locally."); + let mut file_write = fs::OpenOptions::new() + .write(true) + .append(false) + .open(&*LOCAL_HASH_PATH) + .unwrap(); + + if let Err(e) = writeln!(file_write, "{}", &json) { + eprintln!("Couldn't write to file: {}", e); + } process::exit(0); } @@ -62,15 +90,13 @@ fn main() -> std::io::Result<()> { let mut hash_dict: Vec = vec![]; - // TODO: use a real fucking argument parser. + // TODO: argument parser lol. let args: Vec = env::args().collect(); let wordlist_file = &args[1]; - // println!("📋 Wordlist: {}", wordlist_file); - // check for saved hashes locally - // BUGS: file is overwriting, not appending. - // TODO: read the entire local file to memory before writing. + fs::create_dir_all(format!("{}/.ruo", env::home_dir().unwrap().display()))?; + let f = fs::File::open(&*LOCAL_HASH_PATH); let _ = match f { Ok(file) => file, @@ -83,22 +109,16 @@ fn main() -> std::io::Result<()> { }, }; - let json_file_path = Path::new(&*LOCAL_HASH_PATH); - - let data = fs::read_to_string(json_file_path).unwrap(); - - let mut local_hive: Vec = Vec::new(); - if fs::metadata(json_file_path).unwrap().len() != 0 { - local_hive = serde_json::from_str(&data)?; - } + let local_hive = load_local_hive(); + // check if the current hash matches to the hash in the local_hive. for hash_object in local_hive { - // check if the current hash matches to the hash in the local_hive. if hash_object.hash == *HASH_INPUT { println!( "🤍 Saved hash found! {} -> \"{}\"", hash_object.hash, hash_object.plaintext ); + process::exit(0); } } @@ -144,11 +164,13 @@ fn main() -> std::io::Result<()> { hash_dict.push(line?.trim_end().to_string()); } + // debug unsafe { LOAD_TIME = now.elapsed().as_millis(); println!("loaded the wordlist file in {} millisecs.", LOAD_TIME); } + // rayon goes brr hash_dict.par_iter().for_each(|lines| { let line = lines.clone(); crack(line, hash_len, now);