Why do most hashing functions produce hashes that have characters a-f 0-9?

It's just hex encoded. A 16 byte md5 hash can contain non-printable characters, so it's encoded to a 32 char hex string.


As others have responded, hash functions (all of them, including MD5, SHA-256, Whirlpool and the dozens of other functions) output bits. The output of MD5 is 128 bits. However, humans are bad at reading bits. Humans are good at reading characters. So, when a hash function output is meant for human consumption, it is converted to characters with some encoding.

Hexadecimal is one of the simplest encoding of bits into characters. It converts a chunk of four bits into a digit or a character in the 'a' to 'f' range. Other encodings exist, e.g. Base64, which uses a bigger alphabet (64 signs instead of 16) and is more compact (the 128-bit output of MD5 is encoded as 24 characters in Base64, vs 32 in hexadecimal), but is a bit more complex to implement.

There are many possible variants with hexadecimal; e.g. we can add some spaces every few characters (to ease reading), or other punctuation such as colon signs (':'); we can use uppercase or lowercase letters. Tradition for hash function outputs is to use lowercase with no space or punctuation. This tradition was already in force in the infancy of MD5: MD5 has been designed in 1991, published in April 1992 as RFC 1321; as you can see in that document (near the end, section A.5), hash outputs already use lowercase hexadecimal.