Java · Course navigation

Java: SHA-256 hashing for integrity

Compute a SHA-256 digest with MessageDigest and see that a tiny change produces a completely different value.

On this page
Before you start

Java strings, bytes, and exceptions.

  • Compute a SHA-256 digest with MessageDigest and see that a tiny change produces a completely different value.
  • Predict the sample output and explain the state changes.
  • Complete the practice task and check the boundary cases.

The concept

A cryptographic hash function turns any input into a fixed-size digest. It is deterministic, one-way, and designed so that a tiny change in the input changes the digest unpredictably. SHA-256 produces 32 bytes, shown here as 64 hexadecimal characters.

Hashes are used to check integrity: if a downloaded file's digest matches the published one, the file was not corrupted or altered. MessageDigest.isEqual compares two byte arrays in constant time, which avoids leaking how many leading bytes matched. A plain fast hash is not suitable for storing passwords.

Code example

Java
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;

class Main {
  static String hex(byte[] bytes) {
    StringBuilder sb = new StringBuilder();
    for (byte b : bytes) {
      sb.append(String.format("%02x", b));
    }
    return sb.toString();
  }

  public static void main(String[] args) throws Exception {
    MessageDigest sha = MessageDigest.getInstance("SHA-256");
    String a = hex(sha.digest("abc".getBytes(StandardCharsets.UTF_8)));
    String b = hex(sha.digest("abd".getBytes(StandardCharsets.UTF_8)));
    System.out.println(a);
    System.out.println(b);
    System.out.println(MessageDigest.isEqual(a.getBytes(StandardCharsets.UTF_8), a.getBytes(StandardCharsets.UTF_8)));
  }
}
Output
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
a52d159f262b2c6ddb724a61840befc36eb30c88877a4030b65cbe86298449c9
true

Follow the code

Open the walkthrough to inspect the example one step at a time.

Show guided walkthrough
Guided walkthroughReady
1import java.nio.charset.StandardCharsets;
2import java.security.MessageDigest;
3
4class Main {
5 static String hex(byte[] bytes) {
6 StringBuilder sb = new StringBuilder();
7 for (byte b : bytes) {
8 sb.append(String.format("%02x", b));
9 }
10 return sb.toString();
11 }
12
13 public static void main(String[] args) throws Exception {
14 MessageDigest sha = MessageDigest.getInstance("SHA-256");
15 String a = hex(sha.digest("abc".getBytes(StandardCharsets.UTF_8)));
16 String b = hex(sha.digest("abd".getBytes(StandardCharsets.UTF_8)));
17 System.out.println(a);
18 System.out.println(b);
19 System.out.println(MessageDigest.isEqual(a.getBytes(StandardCharsets.UTF_8), a.getBytes(StandardCharsets.UTF_8)));
20 }
21}

Follow the example

Start to inspect the source, values, and output. These prepared steps explain the published sample; grouped loop steps describe multiple iterations.

View the complete dry-run table
Prepared trace of the published program. Some rows group repeated iterations.
Step / lineWhat happensState after stepOutput so far
Create a SHA-256 digest engine.—
—
Hash the bytes of abc. This is a standard SHA-256 test vector.32 bytes → 64 hex characters
—
Print the digest of abc.32 bytes → 64 hex characters
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
Changing one letter produces a completely different digest.32 bytes → 64 hex characters
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
a52d159f262b2c6ddb724a61840befc36eb30c88877a4030b65cbe86298449c9
A constant-time comparison of equal values returns true.32 bytes → 64 hex characters
ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad
a52d159f262b2c6ddb724a61840befc36eb30c88877a4030b65cbe86298449c9
true

Behind the scenes

How Java processes this code

The Java compiler produces bytecode. The JVM loads the class and invokes its main method.

Cost and common mistakes

O(m) time for an m-byte input and a fixed 32-byte output.

  • Always convert text to bytes with an explicit charset such as UTF-8, otherwise the digest depends on the platform default.
  • Plain SHA-256 is fast, which helps attackers who guess passwords. Use a slow, salted password hash for passwords.
  • MD5 and SHA-1 are broken for collision resistance and must not be used for new security work.

Try it yourself

How can you check a downloaded file against a published digest?

Reveal answer and reasoning

Hash the file's bytes with the same algorithm and compare the hex result with the published value; they must match exactly.

Further reading