hash
Hash identification, password cracking, rainbow tables, salted hashes, PBKDF2, and timing-safe comparison.
Load with: use hash
What this module does
hash is built around cracking and identifying password hashes.
Given a hash string it can tell you what algorithm produced it, then crack it
via brute-force (up to 2-character candidates from a charset) or a dictionary attack.
It also builds rainbow chains, generates salted hashes, wraps PBKDF2, and provides
a timing-safe comparison to prevent timing attacks when verifying hashes.
Hashing delegates to cry for MD5 and SHA-256. SHA-1 and SHA-512 call
host native functions (__hash_sha1, __hash_sha512).
The hash.* aliases provide a clean public API over the raw function names.
Quick example
use hash
# Identify a hash by its format
prn(hashi("5f4dcc3b5aa765d61d8327deb882cf99")) # "md5"
prn(hashi("$2b$10$...")) # "bcrypt"
# Dictionary crack with the built-in common password list
result = hashd("5f4dcc3b5aa765d61d8327deb882cf99", hashw())
prn(result.found) # tru
prn(result.password) # "password"
# Timing-safe comparison
ok = hasht(submitted_hash, stored_hash)
Functions
Hash identification
hashi(hash_str)
Identifies the algorithm that produced a hash string by inspecting its length and prefix. Returns a string label:
- 32 hex chars →
"md5" - 40 hex chars →
"sha1" - 64 hex chars →
"sha256" - 128 hex chars →
"sha512" - Prefix
$2a$/$2b$/$2y$→"bcrypt" - Prefix
$6$→"sha512crypt" - Prefix
$5$→"sha256crypt" - Prefix
$1$→"md5crypt" - Prefix
$apr1$→"apr1" - Prefix
sha1$→"sha1django" - Prefix
pbkdf2_sha256$→"pbkdf2_sha256" - Prefix
scrypt$→"scrypt" - Prefix
argon2→"argon2" - Anything else →
"unknown"
Hash algorithms
hashm(s) / hash.md5(s)
MD5 digest of s. Delegates to cry.crymd.
hash1(s) / hash.sha1(s)
SHA-1 digest of s. Calls the host native __hash_sha1.
hash2(s) / hash.hashs(s)
SHA-256 digest of s. Delegates to cry.s25.
hash5(s) / hash.sha512(s)
SHA-512 digest of s. Calls the host native __hash_sha512.
hashx(w, t)
Dispatches to the right hash function based on a type label from hashi. Supports "md5", "sha1", "sha256". Falls back to SHA-256 for anything else.
hash.hashm(d, k)
HMAC - computes cry.cryhm(k, d). k is the key, d is the data.
hash.hashr(s)
Non-cryptographic deterministic integer from a string - uses a polynomial rolling hash (x = x * 31 + ord(c) mod 1000000007). Good for bucketing, not security.
Cracking
hashb(hash_str, charset, max_len)
Brute-force crack. Generates all 1- and 2-character candidates from charset
using hashg, hashes each one with the algorithm identified by hashi,
and returns the first match. Returns {found: tru, password, attempts} on success,
or {found: fls, attempts} if nothing matched.
Note: currently generates up to 2-character candidates only.
hashg(charset, max_len)
Generates the candidate list for brute-force: all single characters from charset,
then all 2-character combinations. The max_len parameter is accepted but the
current implementation generates 1- and 2-character strings only.
hashd(hash_str, wordlist)
Dictionary attack. Iterates through wordlist, hashes each word with the
algorithm identified by hashi, and returns the first match.
Returns {found: tru, password, attempts} or {found: fls, attempts}.
hashmx(hashes, wordlist)
Cracks multiple hashes at once from a single wordlist pass. For each word, checks it
against all remaining uncracked hashes. Stops early if all hashes are cracked.
Returns {cracked: [{hash, password}], uncracked: [...]}.
hashw()
Returns a built-in list of 20 common passwords (e.g. "123456", "password", "qwerty") for quick dictionary attacks.
Rainbow tables
hashrr(hash_str, chain_pos, charset)
Reduction function for rainbow tables. Converts a hash back to a plaintext candidate
by using 8 pairs of hex characters from the hash, adding the chain position chain_pos,
and indexing into charset. Returns an 8-character plaintext string.
hashrc(start_plaintext, chain_len, charset)
Walks a rainbow chain starting from start_plaintext for chain_len steps.
Each step: hash the current value with MD5, then reduce with hashrr.
Returns {start, end, length} where end is the MD5 of the final plaintext.
Salted hashes and key derivation
hashsa(password, salt, algo)
Produces a salted hash by concatenating password + salt and hashing with
algo. Supports "md5", "sha256", "sha512".
Errors on unknown algorithms.
hashp(password, salt, iterations)
PBKDF2-SHA256 key derivation. Produces a 32-byte derived key. Delegates to cry.crypb.
Comparison
hasht(a, b) / hash.hashc(a, b)
Timing-safe string comparison. Delegates to cry.cryct. Use this instead of == when comparing hashes to prevent timing oracle attacks.
Notes
hashiidentifies by length first, then prefix - a 32-char string with no$will always be classified as"md5"even if the second length-32 branch is unreachable in practice.- Brute-force (
hashb) only generates 1 and 2-character candidates - it is not suitable for real passwords of any length. - Rainbow chains use MD5 for the hash step. The reduction function reads 8 pairs of hex chars, so it requires hashes of at least 16 characters.
- Always use
hasht/hash.hashcfor hash verification - never==. hash.hashb(blake2) is defined but throws"hash.blake2: not implemented".