# HashSmith
A modern, declarative and compositional password pattern engine and Hashcat orchestrator for Python.
**Docs**: [`github.com/BaksiLi/hashsmith/wiki`](https://github.com/BaksiLi/hashsmith/wiki)
**Blog**: [HashSmith: Crafting Password Patterns for Modern Workflows](https://blog.baksili.codes/hashsmith)
## ✨ Core Features
- **🧱 Compositional**: Build complex patterns from simple, reusable pieces.
- **📝 Declarative**: Describe *what* you want, not *how* to generate it.
- **📖 Readable**: Code structure documents the password pattern.
- **🔧 Extensible**: Easy to add new pattern types and transforms.
- **🧠 Memory Efficient**: Lazy generation for combining patterns to handle massive keyspaces.
## 🚀 Quick Start
```python
from hashsmith.patterns import P, Birthday, Transform
# Build a [word][numbers][suffix] pattern
pattern = (
P(["crypto", "bitcoin"]).expand(Transform.CAPITALIZE) &
(
P(["123", "456", "789"]) |
Birthday(years=[1990, 1995], formats=["MMDD"])
) &
P(["", "!", "$"])
)
# Generate and print the first 10 passwords
passwords = list(pattern.generate(min_len=6, max_len=15))
for p in passwords[:10]:
print(p)
# → crypto123, crypto123!, crypto123$, crypto456, ...
```
## 🧩 Core Components
| Component | Purpose | Example |
|-----------|---------|---------|
| **`P`** | Basic pattern with items | `P(["word1", "word2"])` |
| **`&` (`PAnd`)** | Sequential concatenation | `pattern1 & pattern2` |
| **`\|` (`POr`)** | Alternatives (choose one) | `pattern1 \| pattern2` |
| **Transforms** | Inclusive `.expand()` or exclusive `.alter()` | `P(["a"]).expand(Transform.UPPER)` |
### Additional Patterns
| Pattern | Purpose | Example |
|---------|---------|---------|
| **`Birthday`** | Date-based patterns (calendar-aware) | `Birthday(years=[1990], formats=["MMDD"])` |
**Coming Soon**: `Incremental`, `Charset`, `Keyboard` patterns
## ⚡ Transform System
HashSmith supports two transformation modes:
```python
# Inclusive expansion (adds to the set)
P(["hello"]).expand(Transform.UPPER)
# → ["hello", "HELLO"]
# Exclusive alteration (replaces the set)
P(["hello"]).alter(Transform.UPPER)
# → ["HELLO"]
# Mix alter (exclusive) and expand (inclusive)
# Prefer `.alter()` before `.expand()` when chaining
P(["web"]).alter(Transform.UPPER).expand(Transform.REVERSE)
# → ["WEB", "BEW"]
# Chained expansions accumulate results
P(["hello"]).expand(Transform.UPPER).expand(lambda x: x + "!")
# → ["hello", "HELLO", "hello!", "HELLO!"]
# Available transforms
Transform.UPPER, Transform.LOWER, Transform.CAPITALIZE
Transform.LEET_BASIC # hello → h3ll0
Transform.REVERSE # hello → olleh
Transform.ZERO_PAD_2 # 5 → 05
Transform.REPEAT
```
## 🔥 Attack on Hashes
HashSmith generates wordlists optimized for [Hashcat](https://hashcat.net/hashcat/) attacks:
```python
from hashsmith.attacks import DictionaryAttack
from hashsmith.core import HashcatRunner
# Generate targeted wordlist
pattern = pattern # build your pattern
# save_to_file(pattern, "custom.txt", min_len=8, max_len=16)
# Run hashcat attack
attack = DictionaryAttack("/usr/bin/hashcat")
runner = HashcatRunner("/usr/bin/hashcat")
command = attack.generate_command(
hash_file="hashes.txt",
wordlist="custom.txt",
)
runner.run(command)
```
COMING: Piping with Hashcat.
## 📦 Installation
```bash
# From PyPI (recommended)
pip install hashsmith
# From source
git clone https://github.com/BaksiLi/hashsmith.git
cd hashsmith
pdm install # or: pip install -r requirements.txt
```
## 📖 Development
For development, testing, and contribution guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md).
Raw data
{
"_id": null,
"home_page": null,
"name": "hashsmith",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "password, hashcat, security, patterns, cracking, wordlist",
"author": null,
"author_email": "Baksi Li <myself@baksili.codes>",
"download_url": "https://files.pythonhosted.org/packages/c8/dd/e93d9ab9ac354d4d0ddc553083299a0f771bfb7ed86dd275bf7069129be2/hashsmith-0.2.2.tar.gz",
"platform": null,
"description": "# HashSmith\n\nA modern, declarative and compositional password pattern engine and Hashcat orchestrator for Python.\n\n**Docs**: [`github.com/BaksiLi/hashsmith/wiki`](https://github.com/BaksiLi/hashsmith/wiki)\n**Blog**: [HashSmith: Crafting Password Patterns for Modern Workflows](https://blog.baksili.codes/hashsmith)\n\n## \u2728 Core Features\n\n- **\ud83e\uddf1 Compositional**: Build complex patterns from simple, reusable pieces.\n- **\ud83d\udcdd Declarative**: Describe *what* you want, not *how* to generate it.\n- **\ud83d\udcd6 Readable**: Code structure documents the password pattern.\n- **\ud83d\udd27 Extensible**: Easy to add new pattern types and transforms.\n- **\ud83e\udde0 Memory Efficient**: Lazy generation for combining patterns to handle massive keyspaces.\n\n## \ud83d\ude80 Quick Start\n\n```python\nfrom hashsmith.patterns import P, Birthday, Transform\n\n# Build a [word][numbers][suffix] pattern\npattern = (\n P([\"crypto\", \"bitcoin\"]).expand(Transform.CAPITALIZE) &\n (\n P([\"123\", \"456\", \"789\"]) |\n Birthday(years=[1990, 1995], formats=[\"MMDD\"])\n ) &\n P([\"\", \"!\", \"$\"])\n)\n\n# Generate and print the first 10 passwords\npasswords = list(pattern.generate(min_len=6, max_len=15))\nfor p in passwords[:10]:\n print(p)\n\n# \u2192 crypto123, crypto123!, crypto123$, crypto456, ...\n```\n\n## \ud83e\udde9 Core Components\n\n| Component | Purpose | Example |\n|-----------|---------|---------|\n| **`P`** | Basic pattern with items | `P([\"word1\", \"word2\"])` |\n| **`&` (`PAnd`)** | Sequential concatenation | `pattern1 & pattern2` |\n| **`\\|` (`POr`)** | Alternatives (choose one) | `pattern1 \\| pattern2` |\n| **Transforms** | Inclusive `.expand()` or exclusive `.alter()` | `P([\"a\"]).expand(Transform.UPPER)` |\n\n### Additional Patterns\n\n| Pattern | Purpose | Example |\n|---------|---------|---------|\n| **`Birthday`** | Date-based patterns (calendar-aware) | `Birthday(years=[1990], formats=[\"MMDD\"])` |\n\n**Coming Soon**: `Incremental`, `Charset`, `Keyboard` patterns\n\n## \u26a1 Transform System\n\nHashSmith supports two transformation modes:\n\n```python\n# Inclusive expansion (adds to the set)\nP([\"hello\"]).expand(Transform.UPPER)\n# \u2192 [\"hello\", \"HELLO\"]\n\n# Exclusive alteration (replaces the set)\nP([\"hello\"]).alter(Transform.UPPER)\n# \u2192 [\"HELLO\"]\n\n# Mix alter (exclusive) and expand (inclusive)\n# Prefer `.alter()` before `.expand()` when chaining\nP([\"web\"]).alter(Transform.UPPER).expand(Transform.REVERSE)\n# \u2192 [\"WEB\", \"BEW\"]\n\n# Chained expansions accumulate results\nP([\"hello\"]).expand(Transform.UPPER).expand(lambda x: x + \"!\")\n# \u2192 [\"hello\", \"HELLO\", \"hello!\", \"HELLO!\"]\n\n# Available transforms\nTransform.UPPER, Transform.LOWER, Transform.CAPITALIZE\nTransform.LEET_BASIC # hello \u2192 h3ll0\nTransform.REVERSE # hello \u2192 olleh\nTransform.ZERO_PAD_2 # 5 \u2192 05\nTransform.REPEAT\n```\n\n## \ud83d\udd25 Attack on Hashes\n\nHashSmith generates wordlists optimized for [Hashcat](https://hashcat.net/hashcat/) attacks:\n\n```python\nfrom hashsmith.attacks import DictionaryAttack\nfrom hashsmith.core import HashcatRunner\n\n# Generate targeted wordlist\npattern = pattern # build your pattern\n# save_to_file(pattern, \"custom.txt\", min_len=8, max_len=16)\n\n# Run hashcat attack\nattack = DictionaryAttack(\"/usr/bin/hashcat\")\nrunner = HashcatRunner(\"/usr/bin/hashcat\")\n\ncommand = attack.generate_command(\n hash_file=\"hashes.txt\",\n wordlist=\"custom.txt\",\n)\nrunner.run(command)\n```\n\nCOMING: Piping with Hashcat.\n\n## \ud83d\udce6 Installation\n\n```bash\n# From PyPI (recommended)\npip install hashsmith\n\n# From source\ngit clone https://github.com/BaksiLi/hashsmith.git\ncd hashsmith\npdm install # or: pip install -r requirements.txt\n```\n\n## \ud83d\udcd6 Development\n\nFor development, testing, and contribution guidelines, see [CONTRIBUTING.md](CONTRIBUTING.md).\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A modern, compositional password pattern engine and hashcat orchestrator",
"version": "0.2.2",
"project_urls": {
"Documentation": "https://github.com/BaksiLi/hashsmith#readme",
"Homepage": "https://github.com/BaksiLi/hashsmith",
"Issues": "https://github.com/BaksiLi/hashsmith/issues"
},
"split_keywords": [
"password",
" hashcat",
" security",
" patterns",
" cracking",
" wordlist"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "ae11039a2a8942c2333139b48692e296118d1d39f37c4e63a3e72b29077eeecf",
"md5": "567d30fd446ce33cfbca16d2a4b7633b",
"sha256": "f8c13aff44d2e7e3c745f392be1e8fde41b5ca79fae7aed4438f315f0a7a6b1c"
},
"downloads": -1,
"filename": "hashsmith-0.2.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "567d30fd446ce33cfbca16d2a4b7633b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 13051,
"upload_time": "2025-08-28T13:38:14",
"upload_time_iso_8601": "2025-08-28T13:38:14.769411Z",
"url": "https://files.pythonhosted.org/packages/ae/11/039a2a8942c2333139b48692e296118d1d39f37c4e63a3e72b29077eeecf/hashsmith-0.2.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "c8dde93d9ab9ac354d4d0ddc553083299a0f771bfb7ed86dd275bf7069129be2",
"md5": "f8bf85d565eb5755bb9a02180f98c930",
"sha256": "5f8839a0b47728943aaae8a2fb76243d136d8a5b7fca2dd0c6f8e03a440e5ccf"
},
"downloads": -1,
"filename": "hashsmith-0.2.2.tar.gz",
"has_sig": false,
"md5_digest": "f8bf85d565eb5755bb9a02180f98c930",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 12573,
"upload_time": "2025-08-28T13:38:16",
"upload_time_iso_8601": "2025-08-28T13:38:16.018506Z",
"url": "https://files.pythonhosted.org/packages/c8/dd/e93d9ab9ac354d4d0ddc553083299a0f771bfb7ed86dd275bf7069129be2/hashsmith-0.2.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-28 13:38:16",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "BaksiLi",
"github_project": "hashsmith#readme",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "hashsmith"
}