Hash identification
What a digest tells you about itself, which is less than people expect, and what the answer means once you have it.
A good hash function produces output indistinguishable from random. That is the point, and it is also why identifying one is so limited: the digest carries no version byte, no algorithm marker, nothing. All you get is the length — and every algorithm with the same output size produces output that looks exactly alike.
So identification narrows the field and stops. What settles it is context: the column it came out of, the config file next to it, the library the application imports.
Paste a hash into the decoder →By length
| Hex chars | Bytes | Candidates | Notes |
|---|---|---|---|
| 32 | 16 | MD5, MD4, NTLM, LM | NTLM is unsalted MD4 of the UTF-16LE password. LM appears as two 16-character halves. |
| 40 | 20 | SHA-1, RIPEMD-160 | MySQL 4.1+ writes SHA-1 with a leading *. |
| 56 | 28 | SHA-224, SHA3-224 | Uncommon in the wild. |
| 64 | 32 | SHA-256, SHA3-256, BLAKE2s-256 | The default general-purpose digest today. |
| 96 | 48 | SHA-384, SHA3-384 | Turns up in SRI attributes and TLS suites. |
| 128 | 64 | SHA-512, SHA3-512, BLAKE2b-512, Whirlpool | SHA-512 is faster than SHA-256 on 64-bit hardware. |
Base64 changes the arithmetic but not the principle: a 32-byte digest is 44 base64
characters ending in =. Subresource Integrity writes them that way —
sha384-… — with the algorithm named in front, which is the sensible thing
to do. See the SRI generator.
Formats that name themselves
Password hashes are different, because a password hash has to store its own parameters — the salt and the cost — or it could never be verified again. Modular crypt format puts all of it in one string:
| Prefix | Algorithm | Verdict |
|---|---|---|
$argon2id$ | Argon2id | First choice. Memory-hard; parameters (m=, t=, p=) are in the string. |
$2a$ $2b$ $2y$ | bcrypt | Good. The two digits after are the cost — $2b$12$ is 2¹² rounds. 12 is the current floor. |
$7$, $scrypt$ | scrypt | Good, if the parameters are. |
$y$, $gy$ | yescrypt | Good. The current /etc/shadow default on Debian and Fedora. |
$6$ / $5$ | sha512crypt / sha256crypt | Acceptable, ageing. Salted and iterated, but not memory-hard — far cheaper on a GPU than bcrypt. |
$1$ | md5crypt | Obsolete. Rehash on next login. |
{SSHA}, {SHA} | LDAP | A single unstretched digest, salted at best. Not a password hash in any modern sense. |
If you have found a bare digest in a password column
A 32- or 40-character hex string where a password hash should be is a finding on its own, whether or not it is salted. MD5 and SHA-1 are fast — that is what they were built for — and commodity hardware clears billions of candidates a second against them. Salting stops precomputed tables; it does nothing about the speed, so every password in the list still falls, just individually.
The migration does not require knowing anyone's password:
- Hash the existing digests with Argon2id and store the result —
argon2id(md5(password))— so the fast hash is no longer the stored secret. - Verify by applying the same two steps at login.
- Replace the record with a plain
argon2id(password)the next time that user signs in, and expire the ones that never do.
For the algorithms and parameters themselves, cryptoguides.fyi has working password-hashing recipes in seven languages.
What identification cannot do
- It cannot reverse a hash. Nothing can. What "hash crackers" do is guess inputs and compare — which is fast precisely when the algorithm is fast, hence the whole point of the slow ones.
- It cannot distinguish a salted digest from an unsalted one unless the salt is stored alongside it, as modular crypt does.
- It cannot tell a hash from any other 32 random bytes — an AES key, a session id and a SHA-256 digest of the same length are the same thing to a detector.