diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..3c90bca --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,385 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anstream" +version = "0.6.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "cfg-if" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" + +[[package]] +name = "clap" +version = "4.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "libc" +version = "0.2.174" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pwd_cracker" +version = "0.1.0" +dependencies = [ + "clap", + "rand", + "serde", + "serde_json", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[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 = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e261178 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "pwd_cracker" +version = "0.1.0" +edition = "2024" +authors = ["Your Name "] +description = "A tool to generate common weak passwords based on personal information" + +[dependencies] +clap = { version = "4.0", features = ["derive"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +rand = "0.8" diff --git a/README.md b/README.md index 05b72d6..e3d1dbb 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,173 @@ -# PWDCracker -Automatically generate common weak passwords based on certain rules by inputting personal information +# PWD Cracker - 弱密码生成器 + +一个基于个人信息生成常见弱密码的Rust工具,主要用于安全测试和密码强度评估。 + +## 功能特性 + +- 🔐 基于个人信息生成常见弱密码组合 +- 📝 交互式信息收集界面 +- 💾 支持输出到文件 +- 🔢 可限制生成密码数量 +- ⚡ 高性能Rust实现 +- 🛡️ 仅用于合法安全测试 + +## 密码生成规则 + +本工具会根据输入的个人信息生成以下类型的弱密码: + +### 基础信息组合 +- 姓名、昵称、宠物名等的各种大小写组合 +- 多个字段的组合(如:姓名+昵称) + +### 数字组合 +- 个人信息 + 生日、手机号后4位、幸运数字 +- 常见数字后缀:123, 321, 666, 888, 999等 +- 生日的各种格式组合 + +### 常见弱密码模式 +- 经典弱密码:password, 123456, qwerty等 +- 个人化常见模式:i_love_[姓名], my_[昵称]等 + +### 键盘模式 +- 键盘连续字符:qwerty, asdfgh, 123qwe等 +- 键盘图案:1qaz2wsx, 147258等 + +### 特殊字符组合 +- 个人信息 + 特殊字符:!, @, #, $, %等 + +## 安装和使用 + +### 前置要求 + +- Rust 1.70+ +- Cargo包管理器 + +### 编译项目 + +```bash +# 克隆或下载项目 +cd PWDCracker + +# 编译项目 +cargo build --release +``` + +### 使用方法 + +#### 交互式模式 + +```bash +# 启动交互式输入 +cargo run -- -i + +# 或使用编译后的二进制文件 +./target/release/pwd_cracker -i +``` + +#### 输出到文件 + +```bash +# 将生成的密码保存到文件 +cargo run -- -i -o passwords.txt +``` + +#### 限制输出数量 + +```bash +# 只生成前100个密码 +cargo run -- -i -l 100 +``` + +#### 组合使用 + +```bash +# 交互式输入,限制200个密码,保存到文件 +cargo run -- -i -l 200 -o weak_passwords.txt +``` + +### 命令行参数 + +- `-i, --interactive`: 启动交互式个人信息输入 +- `-o, --output `: 指定输出文件路径 +- `-l, --limit `: 限制生成的密码数量 +- `-h, --help`: 显示帮助信息 +- `-V, --version`: 显示版本信息 + +## 使用示例 + +### 示例输入 + +``` +=== 弱密码生成器 === +请输入个人信息(可选项可直接回车跳过): + +姓名: 张三 +姓氏: 张 +昵称/网名: zhangsan +出生年份 (如: 1990): 1990 +出生月份 (如: 05): 05 +出生日期 (如: 15): 15 +手机号码: 13812345678 +邮箱地址: zhangsan@email.com +宠物名字: 小白 +幸运数字: 8 +公司名称: ABC公司 +学校名称: 清华大学 +``` + +### 示例输出 + +``` +生成了 156 个可能的弱密码: + + 1. 123456 + 2. 123456789 + 3. 5678 + 4. 8 + 5. 90 + 6. abc公司 + 7. admin + 8. guest + 9. i_love_zhangsan + 10. login + ... +``` + +## 安全警告 + +⚠️ **重要提醒**: + +- 本工具仅用于**合法的安全测试**目的 +- 请勿用于任何**非法入侵**或**恶意攻击** +- 仅在**授权范围内**使用此工具 +- 建议使用**强密码**并启用**双因素认证** + +## 技术实现 + +- **语言**: Rust 2021 Edition +- **命令行解析**: clap 4.0 +- **序列化**: serde 1.0 +- **数据结构**: HashSet去重,Vec排序输出 + +## 项目结构 + +``` +PWDCracker/ +├── src/ +│ └── main.rs # 主程序文件 +├── Cargo.toml # 项目配置和依赖 +├── README.md # 项目说明文档 +└── LICENSE # 开源许可证 +``` + +## 贡献指南 + +欢迎提交Issue和Pull Request来改进这个项目! + +## 许可证 + +本项目采用开源许可证,详见LICENSE文件。 + +--- + +**免责声明**: 使用本工具产生的任何后果由使用者自行承担,开发者不承担任何责任。 diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..97d3a28 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,368 @@ +use clap::{Arg, Command}; +use serde::{Deserialize, Serialize}; +use std::collections::HashSet; +use std::io::{self, Write}; + +#[derive(Debug, Serialize, Deserialize)] +struct PersonalInfo { + name: String, + surname: String, + nickname: String, + birth_year: String, + birth_month: String, + birth_day: String, + phone: String, + email: String, + pet_name: String, + favorite_number: String, + company: String, + school: String, +} + +impl PersonalInfo { + fn new() -> Self { + PersonalInfo { + name: String::new(), + surname: String::new(), + nickname: String::new(), + birth_year: String::new(), + birth_month: String::new(), + birth_day: String::new(), + phone: String::new(), + email: String::new(), + pet_name: String::new(), + favorite_number: String::new(), + company: String::new(), + school: String::new(), + } + } +} + +struct PasswordGenerator { + info: PersonalInfo, + passwords: HashSet, +} + +impl PasswordGenerator { + fn new(info: PersonalInfo) -> Self { + PasswordGenerator { + info, + passwords: HashSet::new(), + } + } + + fn generate_passwords(&mut self) { + // 基础信息组合 + self.add_basic_combinations(); + + // 数字组合 + self.add_number_combinations(); + + // 常见弱密码模式 + self.add_common_patterns(); + + // 键盘模式 + self.add_keyboard_patterns(); + + // 特殊字符组合 + self.add_special_combinations(); + } + + fn add_basic_combinations(&mut self) { + let fields = vec![ + &self.info.name, + &self.info.surname, + &self.info.nickname, + &self.info.pet_name, + &self.info.company, + &self.info.school, + ]; + + // 单独字段 + for field in &fields { + if !field.is_empty() { + self.passwords.insert(field.to_lowercase()); + self.passwords.insert(field.to_string()); + self.passwords.insert(capitalize_first(field)); + } + } + + // 两字段组合 + for i in 0..fields.len() { + for j in i + 1..fields.len() { + if !fields[i].is_empty() && !fields[j].is_empty() { + self.passwords.insert(format!("{}{}", fields[i].to_lowercase(), fields[j].to_lowercase())); + self.passwords.insert(format!("{}{}", fields[i], fields[j])); + self.passwords.insert(format!("{}{}", capitalize_first(fields[i]), capitalize_first(fields[j]))); + } + } + } + } + + fn add_number_combinations(&mut self) { + let base_words = vec![ + &self.info.name, + &self.info.surname, + &self.info.nickname, + &self.info.pet_name, + ]; + + let numbers = vec![ + &self.info.birth_year, + &self.info.birth_month, + &self.info.birth_day, + &self.info.favorite_number, + &self.info.phone[self.info.phone.len().saturating_sub(4)..], // 后4位 + ]; + + for word in &base_words { + if !word.is_empty() { + for num in &numbers { + if !num.is_empty() { + self.passwords.insert(format!("{}{}", word.to_lowercase(), num)); + self.passwords.insert(format!("{}{}", word, num)); + self.passwords.insert(format!("{}{}", num, word.to_lowercase())); + self.passwords.insert(format!("{}{}", num, word)); + } + } + + // 常见数字组合 + let common_nums = vec!["123", "321", "666", "888", "999", "000", "111", "222"]; + for num in &common_nums { + self.passwords.insert(format!("{}{}", word.to_lowercase(), num)); + self.passwords.insert(format!("{}{}", word, num)); + } + } + } + + // 生日组合 + if !self.info.birth_year.is_empty() && !self.info.birth_month.is_empty() && !self.info.birth_day.is_empty() { + let birth_combinations = vec![ + format!("{}{}{}", self.info.birth_year, self.info.birth_month, self.info.birth_day), + format!("{}{}", self.info.birth_month, self.info.birth_day), + format!("{}{}", self.info.birth_day, self.info.birth_month), + format!("{}", &self.info.birth_year[2..]), // 年份后两位 + ]; + + for birth in birth_combinations { + self.passwords.insert(birth.clone()); + for word in &base_words { + if !word.is_empty() { + self.passwords.insert(format!("{}{}", word.to_lowercase(), birth)); + self.passwords.insert(format!("{}{}", birth, word.to_lowercase())); + } + } + } + } + } + + fn add_common_patterns(&mut self) { + let common_passwords = vec![ + "password", "123456", "123456789", "qwerty", "abc123", + "password123", "admin", "root", "user", "guest", + "welcome", "login", "pass", "test", "demo", + "12345678", "1234567890", "qwertyuiop", "asdfghjkl", + "zxcvbnm", "iloveyou", "princess", "rockyou", + ]; + + for pwd in common_passwords { + self.passwords.insert(pwd.to_string()); + self.passwords.insert(capitalize_first(pwd)); + self.passwords.insert(pwd.to_uppercase()); + } + + // 与个人信息结合的常见模式 + let base_words = vec![&self.info.name, &self.info.surname, &self.info.nickname]; + for word in &base_words { + if !word.is_empty() { + self.passwords.insert(format!("{}123", word.to_lowercase())); + self.passwords.insert(format!("{}321", word.to_lowercase())); + self.passwords.insert(format!("{}666", word.to_lowercase())); + self.passwords.insert(format!("{}888", word.to_lowercase())); + self.passwords.insert(format!("i_love_{}", word.to_lowercase())); + self.passwords.insert(format!("my_{}", word.to_lowercase())); + } + } + } + + fn add_keyboard_patterns(&mut self) { + let keyboard_patterns = vec![ + "qwerty", "asdfgh", "zxcvbn", "qwertyui", "asdfghjk", + "zxcvbnm", "1qaz2wsx", "qazwsx", "123qwe", "qwe123", + "asd123", "zxc123", "147258", "159357", "741852", + ]; + + for pattern in keyboard_patterns { + self.passwords.insert(pattern.to_string()); + self.passwords.insert(pattern.to_uppercase()); + self.passwords.insert(capitalize_first(pattern)); + } + } + + fn add_special_combinations(&mut self) { + let base_words = vec![&self.info.name, &self.info.surname, &self.info.nickname]; + let special_chars = vec!["!", "@", "#", "$", "%", "*", ".", "_"]; + + for word in &base_words { + if !word.is_empty() { + for special in &special_chars { + self.passwords.insert(format!("{}{}", word.to_lowercase(), special)); + self.passwords.insert(format!("{}{}", special, word.to_lowercase())); + self.passwords.insert(format!("{}{}{}", word.to_lowercase(), special, "123")); + } + } + } + } + + fn get_passwords(&self) -> Vec { + let mut passwords: Vec = self.passwords.iter().cloned().collect(); + passwords.sort(); + passwords + } +} + +fn capitalize_first(s: &str) -> String { + let mut chars: Vec = s.chars().collect(); + if !chars.is_empty() { + chars[0] = chars[0].to_uppercase().next().unwrap_or(chars[0]); + } + chars.into_iter().collect() +} + +fn collect_personal_info() -> PersonalInfo { + let mut info = PersonalInfo::new(); + + println!("=== 弱密码生成器 ==="); + println!("请输入个人信息(可选项可直接回车跳过):\n"); + + print!("姓名: "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut info.name).unwrap(); + info.name = info.name.trim().to_string(); + + print!("姓氏: "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut info.surname).unwrap(); + info.surname = info.surname.trim().to_string(); + + print!("昵称/网名: "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut info.nickname).unwrap(); + info.nickname = info.nickname.trim().to_string(); + + print!("出生年份 (如: 1990): "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut info.birth_year).unwrap(); + info.birth_year = info.birth_year.trim().to_string(); + + print!("出生月份 (如: 05): "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut info.birth_month).unwrap(); + info.birth_month = info.birth_month.trim().to_string(); + + print!("出生日期 (如: 15): "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut info.birth_day).unwrap(); + info.birth_day = info.birth_day.trim().to_string(); + + print!("手机号码: "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut info.phone).unwrap(); + info.phone = info.phone.trim().to_string(); + + print!("邮箱地址: "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut info.email).unwrap(); + info.email = info.email.trim().to_string(); + + print!("宠物名字: "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut info.pet_name).unwrap(); + info.pet_name = info.pet_name.trim().to_string(); + + print!("幸运数字: "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut info.favorite_number).unwrap(); + info.favorite_number = info.favorite_number.trim().to_string(); + + print!("公司名称: "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut info.company).unwrap(); + info.company = info.company.trim().to_string(); + + print!("学校名称: "); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut info.school).unwrap(); + info.school = info.school.trim().to_string(); + + info +} + +fn main() { + let matches = Command::new("PWD Cracker") + .version("0.1.0") + .author("Your Name") + .about("根据个人信息生成常见弱密码") + .arg( + Arg::new("interactive") + .short('i') + .long("interactive") + .help("交互式输入个人信息") + .action(clap::ArgAction::SetTrue), + ) + .arg( + Arg::new("output") + .short('o') + .long("output") + .value_name("FILE") + .help("输出文件路径") + .action(clap::ArgAction::Set), + ) + .arg( + Arg::new("limit") + .short('l') + .long("limit") + .value_name("NUMBER") + .help("限制输出密码数量") + .action(clap::ArgAction::Set), + ) + .get_matches(); + + let info = if matches.get_flag("interactive") { + collect_personal_info() + } else { + println!("使用 -i 或 --interactive 参数进入交互模式"); + return; + }; + + println!("\n正在生成密码..."); + + let mut generator = PasswordGenerator::new(info); + generator.generate_passwords(); + + let mut passwords = generator.get_passwords(); + + // 限制输出数量 + if let Some(limit_str) = matches.get_one::("limit") { + if let Ok(limit) = limit_str.parse::() { + passwords.truncate(limit); + } + } + + println!("\n生成了 {} 个可能的弱密码:\n", passwords.len()); + + // 输出到文件或控制台 + if let Some(output_file) = matches.get_one::("output") { + match std::fs::write(output_file, passwords.join("\n")) { + Ok(_) => println!("密码已保存到文件: {}", output_file), + Err(e) => eprintln!("保存文件失败: {}", e), + } + } else { + for (i, password) in passwords.iter().enumerate() { + println!("{:4}. {}", i + 1, password); + } + } + + println!("\n⚠️ 警告: 这些密码仅用于安全测试目的,请勿用于非法用途!"); + println!("💡 建议: 使用强密码并启用双因素认证来保护您的账户安全。"); +}