How the MD5 hash function works (from scratch)