← Back to Advanced Java Course | Chapter 11: Advanced & Security | Lesson 12 of 19

Java Hashing (MD5, SHA)

What is Hashing?

Hashing converts arbitrary input data into a fixed-length string of characters that acts as a unique mathematical fingerprint of that data. It's a deliberately one-way process -- there's no algorithm to reverse a hash back into its original input, which is exactly the property that makes it useful for verifying data or storing passwords.

Example: What is Hashing?

java
import java.security.MessageDigest;
public class Main {
	public static void main(String[] args) throws Exception {
		MessageDigest digest = MessageDigest.getInstance("SHA-256");
		byte[] hash = digest.digest("hello".getBytes());
		System.out.println("Fixed length: " + hash.length + " bytes"); // one-way, no reverse algorithm exists
	}
}

MD5 Hashing

MD5 is a legacy, 128-bit hashing algorithm. It's fast, but it has well-documented cryptographic vulnerabilities (including practical collision attacks), so it should never be used to secure passwords or anything else where security actually matters today.

Example: MD5 Hashing

java
import java.security.MessageDigest;
public class Main {
	public static void main(String[] args) throws Exception {
		MessageDigest digest = MessageDigest.getInstance("MD5"); // fast but has known collision attacks
		byte[] hash = digest.digest("data".getBytes());
		System.out.println(hash.length + " bytes -- never use for passwords");
	}
}

SHA-256 Hashing

SHA-256 is a secure, 256-bit hashing algorithm from the SHA-2 family. It's currently the standard choice for data integrity verification and general cryptographic checks, since no practical attack against it is known at the time of writing.

Example: SHA-256 Hashing

java
import java.security.MessageDigest;
public class Main {
	public static void main(String[] args) throws Exception {
		MessageDigest digest = MessageDigest.getInstance("SHA-256"); // current standard for integrity checks
		byte[] hash = digest.digest("data".getBytes());
		StringBuilder hex = new StringBuilder();
		for (byte b : hash) hex.append(String.format("%02x", b));
		System.out.println(hex);
	}
}

Password Salting

Salting adds a random value (the salt) to a password before hashing it, and stores that salt alongside the resulting hash. This protects against precomputed rainbow-table attacks, since it ensures two users with the identical password still end up with completely different stored hashes.

Example: Password Salting

java
import java.security.*;
public class Main {
	public static void main(String[] args) throws Exception {
		SecureRandom random = new SecureRandom();
		byte[] salt = new byte[16];
		random.nextBytes(salt); // random per user, stored alongside the hash
		MessageDigest digest = MessageDigest.getInstance("SHA-256");
		digest.update(salt);
		byte[] hash = digest.digest("password123".getBytes());
		System.out.println("Salted hash length: " + hash.length);
	}
}

Verifying Hashes

To verify a password later, you regenerate the hash of the newly submitted input using the same algorithm and the same stored salt, then compare the resulting bytes against the stored hash -- never by comparing the original plaintext passwords directly.

Example: Verifying Hashes

java
import java.security.*;
import java.util.Arrays;
public class Main {
	public static void main(String[] args) throws Exception {
		byte[] salt = "fixedSaltForDemo".getBytes();
		MessageDigest digest = MessageDigest.getInstance("SHA-256");
		digest.update(salt);
		byte[] storedHash = digest.digest("password123".getBytes());
		digest.reset();
		digest.update(salt);
		byte[] submittedHash = digest.digest("password123".getBytes()); // recomputed with the same salt
		System.out.println(Arrays.equals(storedHash, submittedHash));
	}
}

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.