Compare commits
	
		
			5 Commits
		
	
	
		
			7a841eac8f
			...
			master
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					bbb9241869 | ||
| 
						 | 
					4302adad55 | ||
| 2953b18df7 | |||
| b4ba730818 | |||
| 01da4a6c39 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					/target
 | 
				
			||||||
							
								
								
									
										45
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					    // Use IntelliSense to learn about possible attributes.
 | 
				
			||||||
 | 
					    // Hover to view descriptions of existing attributes.
 | 
				
			||||||
 | 
					    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
 | 
				
			||||||
 | 
					    "version": "0.2.0",
 | 
				
			||||||
 | 
					    "configurations": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "type": "lldb",
 | 
				
			||||||
 | 
					            "request": "launch",
 | 
				
			||||||
 | 
					            "name": "Debug executable 'all_the_passwords'",
 | 
				
			||||||
 | 
					            "cargo": {
 | 
				
			||||||
 | 
					                "args": [
 | 
				
			||||||
 | 
					                    "build",
 | 
				
			||||||
 | 
					                    "--bin=all_the_passwords",
 | 
				
			||||||
 | 
					                    "--package=all_the_passwords"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "filter": {
 | 
				
			||||||
 | 
					                    "name": "all_the_passwords",
 | 
				
			||||||
 | 
					                    "kind": "bin"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "args": [],
 | 
				
			||||||
 | 
					            "cwd": "${workspaceFolder}"
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            "type": "lldb",
 | 
				
			||||||
 | 
					            "request": "launch",
 | 
				
			||||||
 | 
					            "name": "Debug unit tests in executable 'all_the_passwords'",
 | 
				
			||||||
 | 
					            "cargo": {
 | 
				
			||||||
 | 
					                "args": [
 | 
				
			||||||
 | 
					                    "test",
 | 
				
			||||||
 | 
					                    "--no-run",
 | 
				
			||||||
 | 
					                    "--bin=all_the_passwords",
 | 
				
			||||||
 | 
					                    "--package=all_the_passwords"
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					                "filter": {
 | 
				
			||||||
 | 
					                    "name": "all_the_passwords",
 | 
				
			||||||
 | 
					                    "kind": "bin"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            "args": [],
 | 
				
			||||||
 | 
					            "cwd": "${workspaceFolder}"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										32
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					# This file is automatically @generated by Cargo.
 | 
				
			||||||
 | 
					# It is not intended for manual editing.
 | 
				
			||||||
 | 
					version = 3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "all_the_passwords"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "num-format",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "arrayvec"
 | 
				
			||||||
 | 
					version = "0.7.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "itoa"
 | 
				
			||||||
 | 
					version = "1.0.10"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "num-format"
 | 
				
			||||||
 | 
					version = "0.4.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "arrayvec",
 | 
				
			||||||
 | 
					 "itoa",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
							
								
								
									
										10
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
				
			|||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "all_the_passwords"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					num-format = "0.4.4"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1,2 +1,8 @@
 | 
				
			|||||||
# all_strings
 | 
					# All Strings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A short bit of code to create every possible string combination of given length, with a given charset. The program outputs the combinations to `stdout` and periodic statistics to `stderr`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This project uses quite a bit of `unsafe` blocks to acheive the equivilent of java's `public static` in the form of `static mut`. I know some people don't like unsafe rust code, if you are one of those people... too bad.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Since this code is just single-threaded I can only get about 5M permutations a second when not IO limited. (Tested by redirecting `stduout` to `/dev/null`). Later on I might make this multi-threaded to speed up the calculation speed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										175
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,175 @@
 | 
				
			|||||||
 | 
					use std::hint::black_box;
 | 
				
			||||||
 | 
					use std::io::{stderr, Write};
 | 
				
			||||||
 | 
					use std::sync::{Arc, RwLock};
 | 
				
			||||||
 | 
					use std::thread::{self, sleep};
 | 
				
			||||||
 | 
					use std::time::{Duration, Instant};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use num_format::{Locale, ToFormattedString};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The length of the combination
 | 
				
			||||||
 | 
					const LEN: usize = 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// How many combinations have we create thus far
 | 
				
			||||||
 | 
					static mut TOTAL: usize = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[allow(dead_code)]
 | 
				
			||||||
 | 
					enum Charset {
 | 
				
			||||||
 | 
					    AllChars,
 | 
				
			||||||
 | 
					    AllAlpha,
 | 
				
			||||||
 | 
					    AllAlphaAndNum
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Charset {
 | 
				
			||||||
 | 
					    fn as_str(&self) -> &'static str {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Charset::AllChars => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.<>/?;':\"[]{}\\|-=_+`~!@#$%^&*() ",
 | 
				
			||||||
 | 
					            Charset::AllAlpha => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
 | 
				
			||||||
 | 
					            Charset::AllAlphaAndNum => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789",
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Pseudo main 
 | 
				
			||||||
 | 
					/// 
 | 
				
			||||||
 | 
					/// Starts the number crunching (blocking on main thread!) and the
 | 
				
			||||||
 | 
					/// timer thread which watches the main thread while
 | 
				
			||||||
 | 
					/// reporting statistics about it. 
 | 
				
			||||||
 | 
					fn start(char_list: &str, output_len: usize) {
 | 
				
			||||||
 | 
					    /// Flag to communicate between main (combination crunching) and
 | 
				
			||||||
 | 
					    /// timer threads.
 | 
				
			||||||
 | 
					    static mut IS_DONE: bool = false;
 | 
				
			||||||
 | 
					    /// Seconds between the calculating p/s and percentage done.
 | 
				
			||||||
 | 
					    const CHECK_IN_DELAY: u64 = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let start = Instant::now();
 | 
				
			||||||
 | 
					    // Try multithreading...
 | 
				
			||||||
 | 
					    let mut tasks = Vec::new();
 | 
				
			||||||
 | 
					    let mut counters = Vec::new();
 | 
				
			||||||
 | 
					    let mut buffers = Vec::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start generating threads
 | 
				
			||||||
 | 
					    for i in char_list.chars() {
 | 
				
			||||||
 | 
					        let counter = Arc::new(RwLock::new(0u128));
 | 
				
			||||||
 | 
					        let buffer = Arc::new(RwLock::new(Vec::new()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        counters.push(counter.clone());
 | 
				
			||||||
 | 
					        buffers.push(buffer.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let copy = char_list.to_owned();
 | 
				
			||||||
 | 
					        let worker = thread::spawn(move || {
 | 
				
			||||||
 | 
					            calc(©, &i.to_string(), output_len, counter, buffer);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        tasks.push(worker);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // A thread just to report stats
 | 
				
			||||||
 | 
					    let timer = thread::spawn(move || {
 | 
				
			||||||
 | 
					        let mut out = stderr();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        while unsafe { !IS_DONE } {
 | 
				
			||||||
 | 
					            let mut seconds_elapsed = start.elapsed().as_secs() as u128;
 | 
				
			||||||
 | 
					            // prevent div by zero err
 | 
				
			||||||
 | 
					            if seconds_elapsed == 0 { seconds_elapsed = 1; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mut combinations =0;
 | 
				
			||||||
 | 
					            for i in &counters {
 | 
				
			||||||
 | 
					                combinations += *i.read().unwrap();
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // This doesn't free the memory fast enough! // FIXME
 | 
				
			||||||
 | 
					            for i in &buffers {
 | 
				
			||||||
 | 
					                for j in &*i.read().unwrap() {
 | 
				
			||||||
 | 
					                    let x = j;
 | 
				
			||||||
 | 
					                    black_box(x);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                // prevent memory footprint from getting too big
 | 
				
			||||||
 | 
					                i.write().unwrap().clear();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let time_remaining = {
 | 
				
			||||||
 | 
					                let seconds_remaining = (unsafe {TOTAL as u128} - combinations) * seconds_elapsed;
 | 
				
			||||||
 | 
					                // TODO hours in inacuate?
 | 
				
			||||||
 | 
					                let hours = (seconds_remaining / 60) / 60;
 | 
				
			||||||
 | 
					                let minutes = (seconds_remaining / 60) % 60;
 | 
				
			||||||
 | 
					                let seconds = seconds_remaining % 60;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                format!("{hours}h:{minutes}m:{seconds}s")
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // output stats
 | 
				
			||||||
 | 
					            let _ = out.write(
 | 
				
			||||||
 | 
					                format!("\rCalculated {}, at {}p/s, {:.5}%, elapsed: {}s {}",
 | 
				
			||||||
 | 
					                    combinations.to_formatted_string(&Locale::en_NA),
 | 
				
			||||||
 | 
					                    (combinations / seconds_elapsed).to_formatted_string(&Locale::en_NA),
 | 
				
			||||||
 | 
					                    combinations as f64 / unsafe { TOTAL as f64 } * 100f64,
 | 
				
			||||||
 | 
					                    seconds_elapsed,
 | 
				
			||||||
 | 
					                    time_remaining
 | 
				
			||||||
 | 
					                ).as_bytes());
 | 
				
			||||||
 | 
					            let _ = out.flush();
 | 
				
			||||||
 | 
					            sleep(Duration::from_secs(CHECK_IN_DELAY));
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Block waiting for all the tasks to finish
 | 
				
			||||||
 | 
					    for i in tasks {i.join().unwrap();} 
 | 
				
			||||||
 | 
					    unsafe { IS_DONE = true; }
 | 
				
			||||||
 | 
					    timer.join().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    eprintln!("\r{}ms to calculate the {} permutations (p) for {} chars (n) across {} slots (r).",
 | 
				
			||||||
 | 
					        start.elapsed().as_millis().to_formatted_string(&Locale::en_NA),
 | 
				
			||||||
 | 
					        unsafe {TOTAL}.to_formatted_string(&Locale::en_NA),
 | 
				
			||||||
 | 
					        char_list.len(),
 | 
				
			||||||
 | 
					        output_len);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn main() {
 | 
				
			||||||
 | 
					    let charset = Charset::AllAlpha.as_str();
 | 
				
			||||||
 | 
					    // All the status messages are printed on stderr
 | 
				
			||||||
 | 
					    // This way you can pipe the actual permutations into
 | 
				
			||||||
 | 
					    // a file whilst still getting debug messages. 
 | 
				
			||||||
 | 
					    let t = (charset.len() as u128).pow(LEN.try_into().unwrap());
 | 
				
			||||||
 | 
					    unsafe { TOTAL = t as usize };
 | 
				
			||||||
 | 
					    eprintln!(
 | 
				
			||||||
 | 
					        "\nCalculating {} combinations...\n(Number may be truncated if too large)\n",
 | 
				
			||||||
 | 
					        unsafe { TOTAL }.to_formatted_string(&Locale::en_NA)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    start(&charset, LEN);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Recursively create and print every combination of
 | 
				
			||||||
 | 
					/// `choices` chars inside a string of `len` length.
 | 
				
			||||||
 | 
					/// 
 | 
				
			||||||
 | 
					/// 
 | 
				
			||||||
 | 
					/// * `choices` string containing all the chars you wish
 | 
				
			||||||
 | 
					/// to build random strings with. 
 | 
				
			||||||
 | 
					/// 
 | 
				
			||||||
 | 
					/// * `prefix` should be a blank string `""` unless you
 | 
				
			||||||
 | 
					/// actually want a prefix on every output. This variable is
 | 
				
			||||||
 | 
					/// mainly used within the recursive nature of the function.
 | 
				
			||||||
 | 
					/// 
 | 
				
			||||||
 | 
					/// * `len` the size that all the output strings wil be.
 | 
				
			||||||
 | 
					/// 
 | 
				
			||||||
 | 
					/// * `counter` what to count into
 | 
				
			||||||
 | 
					fn calc(choices: &str, prefix: &str, len: usize, counter: Arc<RwLock<u128>>, buffer: Arc<RwLock<Vec<String>>>) {
 | 
				
			||||||
 | 
					    let need_to_fill = len - prefix.len();
 | 
				
			||||||
 | 
					    match need_to_fill {
 | 
				
			||||||
 | 
					        // the last char in the sequence, time to print
 | 
				
			||||||
 | 
					        1 => {
 | 
				
			||||||
 | 
					            for i in choices.chars() {
 | 
				
			||||||
 | 
					                // This line causes a 10x slowdown
 | 
				
			||||||
 | 
					                buffer.write().unwrap().push(format!("{}{}", prefix, i));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Needs to be in two lines like this, otherwise the write blocks on the read.
 | 
				
			||||||
 | 
					                let temp = *counter.read().unwrap();
 | 
				
			||||||
 | 
					                *counter.write().unwrap() = temp+1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // need to recurse farther into the sequence
 | 
				
			||||||
 | 
					        _ => {
 | 
				
			||||||
 | 
					            for i in choices.chars() {
 | 
				
			||||||
 | 
					                calc(choices, &(prefix.to_string() + &i.to_string()), len, counter.clone(), buffer.clone());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user