Hanzkrafted.IO

Introduction to Hashing

Shoeb Ilyas - November 7, 2026 - 1260 Words

An ideal hash function is a function that always takes an input and always returns a fixed-size output that uniquely corresponds to the given input. The input value we provide is called a message. The hash function runs a series of bit operations and compressions and other algorithms on the message and the output is a fixed-size value. This is the process that is termed as hashing in cryptography.

Let's say we have hash function that generates hash values of 16 bytes for any given input message. A message value of 'cat' will produce same length digest as a message value of 'this is a hashing func' will except in their value.

You can copy and play around with the following code as well. Additionally, I will recommend you to go through the function definitions and read through the code comments as well for a better understanding.

js
//  We are using the official Node.JS crypto module that is used in almost all cryptographic operations.
const crypto = require("crypto");

 // This method returns a hash function for the hash algorithm we provide. 
 // In the code example below, we are using SHA256. 
const hashFunc = crypto.createHash("sha256");

// This function adds the provided input text to our message with the provided encoding that defaults to UTF-8. 
hashFunc.update("this is hashing func");

// Digest is the function that runs the hash function and outputs the hash value
console.log(hashFunc.digest().toString("hex"));

Run this code with multiple different message values and you will get different hash values but with exactly the same byte length of 32 since we are using SHA256. More on that later.

shell
> node index.js --value=cat
> 29194d19c965bd69ed8de93a4407be0ef2cb132c315aed0baf8abe35589be462
>
> node index.js --value="this is hashing func"
> 91e7cb6f55d4854831ffa790d6d84da6838f81595a61d0c37216c8c5615eb129

A perfect hash function generates unique hash for each input. However, in our practical world, there are infinite number of collisions that can happen for a given message. A good hash function aims to minimize the collision rate.

For a given message, we will always receive the same digest.

Features of Cryptographically Secure Hash

  1. Pre-image Resistance: Pre-image refers to the message. Pre-image resistance means, it cannot be derived from a Hash value. Hashing is one direction only.
  2. Second Pr-image Resistance: Given a message and a hash value, it should be impossible to derive another pre-image with the same digest.
  3. Collision resistance: Ideally, two messages should not give us the same hash value. Practically speaking, it must be computationally infeasible to find collisions.
  4. Avalanche Effect: Changing even a single bit in our pre-image should result in a completely new hash value that has no relation to the original pre-image.

There are numerous implications of hashing. It's used in verifying digital certificates. It's also important in electronic signatures. It's used to verify the credibility of the data and to mitigate any man-in-the-middle tampering with our messages in communicating through an open channel. This is what message authentication codes deal with. We'll look into this practical real-life use case scenario in the next article.

Hashing Algorithms

We have multiple hashing algorithms that we can use to generate hash values for our messages. It's going to be out of scope to discuss the inner working and implementation of these algorithms and we will touch on a high level for each of these algorithms. However, if you are interested in deep diving further, I will attach some good resources in the references section.

MD5

MD5 was developed by Ronald Rivest in 1991 as an improvement over MD4. It takes an input message and generates a fixed-sized message of 16 bytes (128 bits).

It was proven to be broken in 2004 by Xiaoyun Wang and his team who demonstrated by simulating a collision attack and generating two different inputs with the same hash value in just hours. Therefore, it's not safe to use for cryptographic purposes.

It's still used in legacy hash systems for non-security cryptography.

SHA1

SHA1 takes an input message and generates fixed-size digest of 160 bits in length. It was used as a Federal Information Processing Standard (FIPS).

In 2017, Google and CWI Amsterdam publicly proved that it was broken by demonstrating a real-world collision with two distinct input PDF files that shared the same digest. From thereon, it's considered broken and not at all recommended to be used in security systems.

SHA-2 & SHA-3

SHA-2 and SHA-3 both belong to the family of SHA family. SHA-2 was developed by NIST in 2001 as a successor to SHA-1 hashing algorithm. It's the default choice for any security system. Both SHA-2 and SHA-3 are not even theoretically broken yet. If you are unsure which hashing algorithm to choose for your cryptography purposes, SHA-2 is a secure choice to opt for.

SHA-2 is used in web security and protocols for secure SSL/TLS certifications, cryptocurrencies and blockchain, digital signatures, secure password hashing, and it's required by law for protecting unclassified U.S. Government information.

We have two main algorithms in SHA-2 - SHA-256 and SHA-512. SHA-256 generates a digest of 256 bits in length while SHA-512 produces a digest of 512 in length. The digest generated by SHA-3 is arbitrary in length.

In the next section we will look into why SHA-256 is so secure.

Breaking SHA256 Hash Algorithm

Let's understand the concept of collisions. This is important for us to understand why breaking SHA-256 and newer secure algorithms computationally impossible for us. Then we'll look into the types of cyber attacks to fully grasp the picture on why SHA-256 and above is not proven to be broken yet. We will not be mentioning SHA-512 or SHA-3 family because the same logic that we study in this section, applies there as well.

Understanding Hash Collisions

In the previous section you read that a perfect hash function generates zero collisions and a good hash function aims to minimize collisions. We also mentioned that theoretically, we have infinite number of collisions in a hash function. Let's create a solid mental model instead of just theory.

1 / 7
A hash maps messages to fixed-size digests

Our toy hash function F1 outputs a 4-bit digest, so there are only 2⁴ = 16 possible digests.

digests
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111

Let's say, we have a hash function, F1, that is a bijection for our demonstration purpose. F1 generates digest of 4 bits in size. Now, we have 4 bit values in our message space, M1. We have to map these values to the digest. This maps cleanly without any collision.

Let's say we have another message space, M2, that contains 5 bit values. We have to map these 5 bit values to our digest space. Let's define another function F2 that maps these 5-bit values. However, our message space is larger than the digest space and therefore we will always have collisions. In our case, we will have at least 16 collisions.

Now, let's take practical examples to further our understanding. Our message space is theoretically infinite because there's no cap on the message length. Let's consider SHA-256 as our hashing function. It's one of the most commonly used hashing algorithms. It produces digest of length 256 bits. This means we have 2256 digest space which is approximately 1.6 x 1077. This huge digest space is unfathomable. Given the infinite number of messages, we will have infinite number of collisions. However, the digest space is so large that finding a collision is computationally impossible for us.

That's it for this article. Hope you found this useful. In the next article, we will look into message authentication codes.