{"id":21586043,"url":"https://github.com/magiclen/passwords","last_synced_at":"2025-08-20T12:31:29.470Z","repository":{"id":57653387,"uuid":"147705808","full_name":"magiclen/passwords","owner":"magiclen","description":"This crate provides useful tools to generate multiple readable passwords, as well as analyze and score them.","archived":false,"fork":false,"pushed_at":"2023-09-11T05:08:19.000Z","size":1081,"stargazers_count":43,"open_issues_count":2,"forks_count":7,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-24T15:13:00.301Z","etag":null,"topics":["password","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/magiclen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-09-06T16:58:43.000Z","updated_at":"2024-11-13T23:16:12.000Z","dependencies_parsed_at":"2024-11-24T18:01:10.288Z","dependency_job_id":null,"html_url":"https://github.com/magiclen/passwords","commit_stats":{"total_commits":43,"total_committers":2,"mean_commits":21.5,"dds":"0.023255813953488413","last_synced_commit":"56c2fc5a067f9abd1440742680927214848f3a03"},"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclen%2Fpasswords","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclen%2Fpasswords/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclen%2Fpasswords/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/magiclen%2Fpasswords/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/magiclen","download_url":"https://codeload.github.com/magiclen/passwords/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230423563,"owners_count":18223435,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["password","rust"],"created_at":"2024-11-24T15:12:29.680Z","updated_at":"2024-12-19T11:12:07.692Z","avatar_url":"https://github.com/magiclen.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"Passwords\n====================\n\n[![CI](https://github.com/magiclen/passwords/actions/workflows/ci.yml/badge.svg)](https://github.com/magiclen/passwords/actions/workflows/ci.yml)\n\nThis crate provides useful tools to generate multiple readable passwords, as well as analyze and score them.\n\n## Generator\n\n`PasswordGenerator` can be used for generating passwords which consist optional numbers, lowercase letters, uppercase letters, symbols and spaces.\n\n```rust\nuse passwords::PasswordGenerator;\n\nlet pg = PasswordGenerator {\n       length: 8,\n       numbers: true,\n       lowercase_letters: true,\n       uppercase_letters: true,\n       symbols: true,\n       spaces: true,\n       exclude_similar_characters: false,\n       strict: true,\n   };\n\nprintln!(\"{}\", pg.generate_one().unwrap());\nprintln!(\"{:?}\", pg.generate(5).unwrap());\n```\n\nIt also has a fluent interface.\n\n```rust\nuse passwords::PasswordGenerator;\n\nlet pg = PasswordGenerator::new().length(8).numbers(true).lowercase_letters(true).uppercase_letters(true).symbols(true).spaces(true).exclude_similar_characters(true).strict(true);\n\nprintln!(\"{}\", pg.generate_one().unwrap());\nprintln!(\"{:?}\", pg.generate(5).unwrap());\n```\n\nThe `generate` method has been optimized for multiple generation. Don't reuse the `generate_one` method to generate multiple passwords. If the count of passwords can't be determined, use the `try_iter` method to create a `PasswordGeneratorIter` instance which implements the `Iterator` trait and can re-generate passwords more efficiently.\n\n```rust\nuse passwords::PasswordGenerator;\n\nlet pgi = PasswordGenerator::new().try_iter().unwrap();\n\nprintln!(\"{}\", pgi.generate_one());\nprintln!(\"{:?}\", pgi.generate(5));\n```\n\n```rust\nuse passwords::PasswordGenerator;\n\nlet mut pgi = PasswordGenerator::new().try_iter().unwrap();\n\nprintln!(\"{}\", pgi.next().unwrap());\nprintln!(\"{}\", pgi.next().unwrap());\n```\n\n## Hasher\n\nTo enable hashing functions, you need to enable the **crypto** feature.\n\n```toml\n[dependencies.passwords]\nversion = \"*\"\nfeatures = [\"crypto\"]\n```\n\nThen, `bcrypt`, `identify_bcrypt`, `bcrypt_format`, `identify_bcrypt_format`, `get_password_with_null_terminated_byte` and `gen_salt` functions in the `hasher` module are available.\n\n```rust\nuse passwords::hasher;\n\nlet salt = hasher::gen_salt();\n\nlet hashed = hasher::bcrypt(10, \u0026salt, \"password\\0\").unwrap();\nassert!(unsafe { hasher::identify_bcrypt(10, \u0026salt, \"password\\0\", \u0026hashed) });\n\nlet mcf = hasher::bcrypt_format(10, \u0026salt, \"password\\0\").unwrap();\nassert!(unsafe { hasher::identify_bcrypt_format(\"password\\0\", mcf) });\n```\n\n## Analyzer\n\nThe `analyze` function in the `analyzer` module can be used to create a `AnalyzedPassword` instance which contains some information about the input password.\n\nTypically, we don't want our readable password to contain control characters like BS, LF, CR, etc.\nBefore the analyzer analyzes a password, it filters the password in order to remove its control characters. And after analyzing, the analyzer will return the filtered password.\nTherefore, you can use this analyzer as a password guard before you store the input password (or generally hash it first and then store) to your database.\n\n```rust\nuse passwords::analyzer;\n\nlet password = \"ZYX[$BCkQB中文}%A_3456]  H(\\rg\";\n\nlet analyzed = analyzer::analyze(password);\n\nassert_eq!(\"ZYX[$BCkQB中文}%A_3456]  H(g\", analyzed.password()); // \"\\r\" was filtered\nassert_eq!(26, analyzed.length()); // Characters' length, instead of that of UTF-8 bytes\nassert_eq!(2, analyzed.spaces_count()); // Two spaces between \"]\" and \"H\"\nassert_eq!(4, analyzed.numbers_count()); // Numbers are \"3456\"\nassert_eq!(2, analyzed.lowercase_letters_count()); // Lowercase letters are \"k\" and \"g\"\nassert_eq!(9, analyzed.uppercase_letters_count()); // Uppercase letters are \"ZYX\", \"BC\", \"QB\", \"A\" and \"H\"\nassert_eq!(7, analyzed.symbols_count()); // Symbols are \"[$\", \"}%\", \"_\", \"]\" and \"(\"\nassert_eq!(2, analyzed.other_characters_count()); // Other characters are \"中文\". These characters are usually not included on the rainbow table.\nassert_eq!(2, analyzed.consecutive_count()); // Consecutive repeated characters are \"  \" (two spaces)\nassert_eq!(2, analyzed.non_consecutive_count()); // Non-consecutive repeated characters are \"B\" (appears twice)\nassert_eq!(7, analyzed.progressive_count()); // Progressive characters are \"ZYX\" and \"3456\". \"BC\" is not counted, because its length is only 2, not three or more.\n```\n\nYou can also check whether a password is too simple and dangerous to use, by looking up a *common passwords table*.\nIf you want to do that, you need to enable the **common-password** feature.\n\n```toml\n[dependencies.passwords]\nversion = \"*\"\nfeatures = [\"common-password\"]\n```\nThen, the `is_common_password` function in `analyzer` module and the `is_common` method of a `AnalyzedPassword` instance are available.\n\nYou should notice that after you enable the **common-password** feature, the time for compiling increases dramatically, because the *common passwords table* will be compiled into the executable binary file as a hardcode array.\n\n## Scorer\n\nAfter analyzing a password, you can use the `score` function in the `scorer` module to score it.\n\n```rust\nuse passwords::analyzer;\nuse passwords::scorer;\n\nassert_eq!(62f64, scorer::score(\u0026analyzer::analyze(\"kq4zpz13\")));\nassert_eq!(100f64, scorer::score(\u0026analyzer::analyze(\"ZYX[$BCkQB中文}%A_3456]  H(\\rg\")));\n\nif cfg!(feature = \"common-password\") {\n    assert_eq!(11.2f64, scorer::score(\u0026analyzer::analyze(\"feelings\"))); // \"feelings\" is common, so the score is punitively the original divided by 5\n} else {\n    assert_eq!(56f64, scorer::score(\u0026analyzer::analyze(\"feelings\")));\n}\n```\n\nA password whose score is,\n\n* 0 ~ 20 is very dangerous (may be cracked within few seconds)\n* 20 ~ 40 is dangerous\n* 40 ~ 60 is very weak\n* 60 ~ 80 is weak\n* 80 ~ 90 is good\n* 90 ~ 95 is strong\n* 95 ~ 99 is very strong\n* 99 ~ 100 is invulnerable\n\n## Crates.io\n\nhttps://crates.io/crates/passwords\n\n## Documentation\n\nhttps://docs.rs/passwords\n\n## License\n\n[MIT](LICENSE)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmagiclen%2Fpasswords","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmagiclen%2Fpasswords","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmagiclen%2Fpasswords/lists"}