Files
derp/plugins/hash.py
user 2e2378d3ee feat: add wave 1 plugins (dns, encode, hash, defang, revshell, cidr)
All pure stdlib, zero external dependencies:
- dns: raw UDP resolver with A/AAAA/MX/NS/TXT/CNAME/PTR/SOA
- encode: base64, hex, URL, ROT13 encode/decode
- hash: md5/sha1/sha256/sha512 generation + type identification
- defang: IOC defanging/refanging for safe sharing
- revshell: reverse shell one-liners for 11 languages
- cidr: subnet calculator with IP membership check

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 01:46:13 +01:00

76 lines
2.4 KiB
Python

"""Plugin: hash strings and identify hash types."""
from __future__ import annotations
import hashlib
import re
from derp.plugin import command
_ALGOS = ("md5", "sha1", "sha256", "sha512")
# Patterns for hash identification (length -> possible types)
_HASH_PATTERNS: list[tuple[str, int, str]] = [
(r"^[a-fA-F0-9]{32}$", 32, "MD5"),
(r"^[a-fA-F0-9]{40}$", 40, "SHA-1"),
(r"^[a-fA-F0-9]{56}$", 56, "SHA-224"),
(r"^[a-fA-F0-9]{64}$", 64, "SHA-256 / SHA3-256"),
(r"^[a-fA-F0-9]{96}$", 96, "SHA-384 / SHA3-384"),
(r"^[a-fA-F0-9]{128}$", 128, "SHA-512 / SHA3-512"),
(r"^\$2[aby]\$\d{2}\$.{53}$", 0, "bcrypt"),
(r"^\$6\$", 0, "sha512crypt"),
(r"^\$5\$", 0, "sha256crypt"),
(r"^\$1\$", 0, "md5crypt"),
(r"^[a-fA-F0-9]{16}$", 16, "MySQL 3.x / Half MD5"),
(r"^\*[a-fA-F0-9]{40}$", 0, "MySQL 4.1+"),
]
@command("hash", help="Hash text: !hash [algo] <text>")
async def cmd_hash(bot, message):
"""Generate hash digests.
!hash hello -> MD5, SHA1, SHA256
!hash sha512 hello -> specific algorithm
"""
parts = message.text.split(None, 2)
if len(parts) < 2:
await bot.reply(message, f"Usage: !hash [{'|'.join(_ALGOS)}] <text>")
return
# Check if first arg is an algorithm name
if len(parts) >= 3 and parts[1].lower() in _ALGOS:
algo = parts[1].lower()
text = parts[2]
digest = hashlib.new(algo, text.encode()).hexdigest()
await bot.reply(message, f"{algo}: {digest}")
return
# No algorithm specified -- show all common hashes
text = message.text.split(None, 1)[1]
results = []
for algo in ("md5", "sha1", "sha256"):
digest = hashlib.new(algo, text.encode()).hexdigest()
results.append(f"{algo}:{digest}")
await bot.reply(message, " ".join(results))
@command("hashid", help="Identify hash type: !hashid <hash>")
async def cmd_hashid(bot, message):
"""Identify a hash type by its format and length."""
parts = message.text.split(None, 1)
if len(parts) < 2:
await bot.reply(message, "Usage: !hashid <hash>")
return
value = parts[1].strip()
matches = []
for pattern, _, name in _HASH_PATTERNS:
if re.match(pattern, value):
matches.append(name)
if matches:
await bot.reply(message, f"Possible: {', '.join(matches)}")
else:
await bot.reply(message, f"Unknown hash format (length: {len(value)})")