Commit 90c5ad7d authored by Pascal Engélibert's avatar Pascal Engélibert 🚴
Browse files

Rewrite all, regex

parent e913f3f4
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
dependencies = [
"memchr",
]
[[package]]
name = "ansi_term"
version = "0.11.0"
......@@ -91,18 +100,6 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb"
[[package]]
name = "bstr"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "473fc6b38233f9af7baa94fb5852dca389e3d95b8e21c8e3719301462c5d9faf"
dependencies = [
"lazy_static",
"memchr",
"regex-automata",
"serde",
]
[[package]]
name = "bumpalo"
version = "3.4.0"
......@@ -237,28 +234,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da24927b5b899890bcb29205436c957b7892ec3a3fbffce81d710b9611e77778"
[[package]]
name = "csv"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9d58633299b24b515ac72a3f869f8b91306a3cec616a602843a383acd6f9e97"
dependencies = [
"bstr",
"csv-core",
"itoa",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
dependencies = [
"memchr",
]
[[package]]
name = "digest"
version = "0.9.0"
......@@ -304,10 +279,10 @@ name = "g1force"
version = "0.1.0"
dependencies = [
"bruteforce",
"csv",
"dup-crypto",
"indicatif",
"rayon",
"regex",
"structopt",
]
......@@ -364,12 +339,6 @@ dependencies = [
"regex",
]
[[package]]
name = "itoa"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "js-sys"
version = "0.3.46"
......@@ -516,16 +485,10 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4"
dependencies = [
"byteorder",
"thread_local",
]
[[package]]
......@@ -549,12 +512,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "ryu"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
[[package]]
name = "scopeguard"
version = "1.1.0"
......@@ -685,6 +642,15 @@ dependencies = [
"syn",
]
[[package]]
name = "thread_local"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447"
dependencies = [
"lazy_static",
]
[[package]]
name = "typenum"
version = "1.12.0"
......
......@@ -7,8 +7,8 @@ license = "AGPL3"
[dependencies]
bruteforce = "0.2.0"
csv = "1.1.5"
dup-crypto = { version = "0.38.0", default-features = false, features = ["scrypt"] }
indicatif = "0.15.0"
rayon = "1.5.0"
regex = "1.4.3"
structopt = "0.3.21"
......@@ -4,6 +4,8 @@ Scrypt bruteforce for Duniter currencies
## Build
You need to switch to Rust Nightly first.
cargo build --release
## Use
......@@ -31,4 +33,4 @@ Dictionary attack should be implemented.
## License
GNU AGPL v3, CopyLeft 2020 Pascal Engélibert
GNU AGPL v3, CopyLeft 2020-2021 Pascal Engélibert
#![feature(bool_to_option)]
#![feature(iter_map_while)]
#![feature(maybe_uninit_ref)]
#![feature(str_split_once)]
use bruteforce::{charset::Charset, BruteForce};
use dup_crypto::{
bases::b58::ToBase58,
......@@ -8,7 +13,13 @@ use dup_crypto::{
};
use indicatif::{ProgressBar, ProgressStyle};
use rayon::prelude::*;
use std::{collections::HashMap, io::stdin, sync::Mutex};
use regex::Regex;
use std::{
collections::HashMap,
io::{stdin, BufRead, BufReader},
mem::MaybeUninit,
sync::RwLock,
};
use structopt::StructOpt;
......@@ -19,7 +30,7 @@ const CHARSET: Charset = Charset::new(&[
'5', '6', '7', '8', '9', '_', '.', '-', '!', '@', '*', '$', '?', '&', '%', ' ',
]);
struct PubkeyData {
struct PubkeyMetadata {
amount: u32,
member: bool,
}
......@@ -27,155 +38,223 @@ struct PubkeyData {
#[derive(Clone, Debug, StructOpt)]
#[structopt(name = "g1force")]
pub struct MainOpt {
/// Use metadata in CSV (amount & member)
#[structopt(short, long)]
metadata: bool,
/// Number of iterations
#[structopt(short, long)]
ntests: usize,
/// Use regex (Perl-style)
#[structopt(short, long)]
wanted_pubkey: Option<String>,
regex: bool,
/// Wanted pubkey or regex. If empty, reads stdin.
#[structopt(short, long)]
pubkey: Option<String>,
}
fn main() {
let opt = MainOpt::from_args();
enum InputData {
Pubkey(PublicKey),
PubkeyList(Vec<PublicKey>),
PubkeyListWithMetadata(HashMap<PublicKey, PubkeyMetadata>),
Regex(Regex),
}
if let Some(ref wanted_pubkey) = opt.wanted_pubkey {
let wanted_pubkey = PublicKey::from_base58(&wanted_pubkey).expect("Invalid pubkey");
let generator = KeyPairFromSaltedPasswordGenerator::with_default_parameters();
let progress_bar = ProgressBar::new((opt.ntests as u64).pow(2));
progress_bar.set_style(
ProgressStyle::default_bar().template(
"{elapsed_precise} {eta} {per_sec} {pos}/{len} {percent}% {wide_bar}",
),
);
let mut i = 0usize;
let mut bf1 = BruteForce::new(CHARSET);
let mut buf = Vec::<String>::new();
progress_bar.tick();
loop {
while buf.len() < 16 && i < opt.ntests {
if let Some(s1) = bf1.next() {
buf.push(s1);
i += 1;
} else {
break;
}
impl InputData {
fn new(opt: &MainOpt) -> Self {
if let Some(ref pubkey) = opt.pubkey {
if opt.regex {
Self::Regex(Regex::new(pubkey).expect("Invalid regex"))
} else {
Self::Pubkey(PublicKey::from_base58(pubkey).expect("Invalid pubkey"))
}
if buf.is_empty() {
break;
} else if opt.metadata {
let mut pubkeys = HashMap::<PublicKey, PubkeyMetadata>::new();
for (i, raw_line) in BufReader::new(stdin()).lines().enumerate() {
let raw_line = raw_line.expect("Error reading CSV");
let mut rows = raw_line.split(&[' ', '\t', ',', ';'][..]);
let pubkey = PublicKey::from_base58(
rows.next().expect(&format!("Missing pubkey line {}", i)),
)
.expect(&format!("Invalid pubkey line {}", i));
pubkeys.insert(
pubkey,
PubkeyMetadata {
amount: rows
.next()
.expect(&format!("Missing amount line {}", i))
.parse()
.expect(&format!("Invalid amount line {}", i)),
member: rows.next().expect(&format!("Missing member line {}", i)) == "1",
},
);
}
buf.par_iter().for_each(|s1| {
let mut j = 0usize;
let bf2 = BruteForce::new(CHARSET);
for s2 in bf2 {
let pubkey = generator
.generate(SaltedPassword::new(s1.clone(), s2.clone()))
.public_key();
if wanted_pubkey == pubkey {
eprintln!("Found!");
println!("{}\t{}", s1, s2);
std::process::exit(0);
}
if j >= opt.ntests {
break;
}
j += 1;
}
progress_bar.inc(opt.ntests as u64);
});
buf.clear();
Self::PubkeyListWithMetadata(pubkeys)
} else {
let mut pubkeys = Vec::<PublicKey>::new();
for (i, raw_line) in BufReader::new(stdin()).lines().enumerate() {
let raw_line = raw_line.expect("Error reading CSV");
let pubkey = PublicKey::from_base58(
raw_line
.split_once(&[' ', '\t', ',', ';'][..])
.expect(&format!("Missing pubkey line {}", i))
.0,
)
.expect(&format!("Invalid pubkey line {}", i));
pubkeys.push(pubkey);
}
Self::PubkeyList(pubkeys)
}
eprintln!("Not found...\n");
} else {
eprintln!("Importing data...");
let mut pubkeys = HashMap::<PublicKey, PubkeyData>::new();
let mut reader = csv::Reader::from_reader(stdin());
for raw_line in reader.records().filter_map(|x| x.ok()) {
let mut rows = raw_line.as_slice().split('\t');
let pubkey = PublicKey::from_base58(rows.next().unwrap()).unwrap();
pubkeys.insert(
pubkey,
PubkeyData {
amount: rows.next().unwrap().parse().unwrap(),
member: rows.next().unwrap() == "1",
},
);
}
}
struct Tester<'a> {
pubkey: MaybeUninit<&'a PublicKey>,
pubkey_list: MaybeUninit<&'a Vec<PublicKey>>,
pubkey_list_with_metadata: MaybeUninit<&'a HashMap<PublicKey, PubkeyMetadata>>,
regex: MaybeUninit<&'a Regex>,
/// Returns (match, stop)
test: fn(&Self, &PublicKey) -> (bool, bool),
}
impl<'a> Tester<'a> {
fn new(data: &'a InputData) -> Self {
match data {
InputData::Pubkey(pubkey) => Self {
pubkey: MaybeUninit::new(pubkey),
pubkey_list: MaybeUninit::uninit(),
pubkey_list_with_metadata: MaybeUninit::uninit(),
regex: MaybeUninit::uninit(),
test: Self::test_pubkey,
},
InputData::PubkeyList(pubkey_list) => Self {
pubkey: MaybeUninit::uninit(),
pubkey_list: MaybeUninit::new(pubkey_list),
pubkey_list_with_metadata: MaybeUninit::uninit(),
regex: MaybeUninit::uninit(),
test: Self::test_pubkey_list,
},
InputData::PubkeyListWithMetadata(pubkey_list_with_metadata) => Self {
pubkey: MaybeUninit::uninit(),
pubkey_list: MaybeUninit::uninit(),
pubkey_list_with_metadata: MaybeUninit::new(pubkey_list_with_metadata),
regex: MaybeUninit::uninit(),
test: Self::test_pubkey_list_with_metadata,
},
InputData::Regex(regex) => Self {
pubkey: MaybeUninit::uninit(),
pubkey_list: MaybeUninit::uninit(),
pubkey_list_with_metadata: MaybeUninit::uninit(),
regex: MaybeUninit::new(regex),
test: Self::test_regex,
},
}
}
let found = Mutex::new(Vec::<(PublicKey, String, String)>::new());
let generator = KeyPairFromSaltedPasswordGenerator::with_default_parameters();
let progress_bar = ProgressBar::new((opt.ntests as u64).pow(2));
progress_bar.set_style(
ProgressStyle::default_bar().template(
"{elapsed_precise} {eta} {per_sec} {pos}/{len} {percent}% {wide_bar}",
),
);
let mut i = 0usize;
let mut bf1 = BruteForce::new(CHARSET);
let mut buf = Vec::<String>::new();
progress_bar.tick();
loop {
while buf.len() < 16 && i < opt.ntests {
if let Some(s1) = bf1.next() {
buf.push(s1);
i += 1;
} else {
fn test_pubkey(&self, x: &PublicKey) -> (bool, bool) {
(x == unsafe { self.pubkey.assume_init() }, true)
}
fn test_pubkey_list(&self, x: &PublicKey) -> (bool, bool) {
(unsafe { self.pubkey_list.assume_init() }.contains(x), false)
}
fn test_pubkey_list_with_metadata(&self, x: &PublicKey) -> (bool, bool) {
(
unsafe { self.pubkey_list_with_metadata.assume_init() }.contains_key(x),
false,
)
}
fn test_regex(&self, x: &PublicKey) -> (bool, bool) {
(
unsafe { self.regex.assume_init() }.is_match(&x.to_base58()),
false,
)
}
}
fn main() {
let opt = MainOpt::from_args();
let data = InputData::new(&opt);
let tester = Tester::new(&data);
let generator = KeyPairFromSaltedPasswordGenerator::with_default_parameters();
let progress_bar = ProgressBar::new(opt.ntests as u64);
progress_bar.set_style(
ProgressStyle::default_bar()
.template("{elapsed_precise} {eta} {per_sec} {pos}/{len} {percent}% {wide_bar}"),
);
progress_bar.tick();
let found = RwLock::new(Vec::<(PublicKey, String, String)>::new());
let continue_test = RwLock::new(true);
BruteForce::new(CHARSET)
.enumerate()
.map_while(|(i, s1)| (*continue_test.read().unwrap() && i < opt.ntests).then_some(s1))
.par_bridge()
.for_each(|s1| {
let mut j = 0usize;
for s2 in BruteForce::new(CHARSET) {
let pubkey = generator
.generate(SaltedPassword::new(s1.clone(), s2.clone()))
.public_key();
let (res_match, res_stop) = (tester.test)(&tester, &pubkey);
if res_match {
let mut found = found.write().unwrap();
found.push((pubkey, s1.clone(), s2));
}
if res_stop {
let mut continue_test = continue_test.write().unwrap();
*continue_test = true;
}
if j >= opt.ntests {
break;
}
j += 1;
}
if buf.is_empty() {
break;
}
buf.par_iter().for_each(|s1| {
let mut j = 0usize;
let bf2 = BruteForce::new(CHARSET);
for s2 in bf2 {
let pubkey = generator
.generate(SaltedPassword::new(s1.clone(), s2.clone()))
.public_key();
if pubkeys.contains_key(&pubkey) {
let mut mutex = found.lock().unwrap();
mutex.push((pubkey, s1.clone(), s2));
}
if j >= opt.ntests {
break;
}
j += 1;
}
progress_bar.inc(opt.ntests as u64);
});
buf.clear();
}
progress_bar.inc(1u64);
});
let mut total_amount = 0u32;
let mut total_member = 0u32;
let found = found.into_inner().unwrap();
let found = found.lock().unwrap();
for line in found.iter() {
let data = pubkeys.get(&line.0).unwrap();
total_amount += data.amount;
if data.member {
total_member += 1;
match data {
InputData::PubkeyListWithMetadata(pubkey_list_with_metadata) => {
let mut total_amount = 0u32;
let mut total_member = 0u32;
for (pubkey, s1, s2) in found {
let metadata = pubkey_list_with_metadata.get(&pubkey).unwrap();
total_amount += metadata.amount;
if metadata.member {
total_member += 1;
}
println!(
"{}\t{}\t{}\t{}\t{}",
pubkey.to_base58(),
s1,
s2,
metadata.amount,
metadata.member as u8,
);
}
println!(
"{}\t{}\t{}\t{}\t{}",
line.0.to_base58(),
line.1,
line.2,
data.amount,
data.member as u8
);
}
eprintln!("Total amount: {}", total_amount);
eprintln!("Total member: {}", total_member);
eprintln!("");
eprintln!("Total amount: {}", total_amount);
eprintln!("Total member: {}", total_member);
}
_ => {
for (pubkey, s1, s2) in found {
println!("{}\t{}\t{}", pubkey.to_base58(), s1, s2);
}
}
}
eprintln!();
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment