Tuesday, 2 January 2024

Get the hash or message digest of a file in Java

Message Digest

A message digest serves as a digital fingerprint for data. It is a fixed-length, distinct string of characters created by a cryptographic hash function. 

 


 

Here's the process:

 

a.   Any data, whether it's a message, a file, or an entire disk, is input into the hash function.

b.   The function then processes and transforms the data using a complex algorithm, generate a unique character string known as the "message digest."

c.    This digest maintains a fixed size, independent of the original data's size. A minor alteration in the original data will lead to a different message digest.

 

Benefits of Message Digest

a.   Ensuring Data Integrity: By comparing the message digest of a received file with the original digest provided by the source, you can confirm that the file has remained uncorrupted during its transmission.

b.   Identifying Data Tampering: Since any modification to the data alters its message digest, it becomes simple to detect any tampering or unintentional errors.

c.    Secure Password Storage: Applications typically store passwords in the form of message digests rather than plain text. This means that even if a database is compromised, the attackers cannot directly obtain your actual password.

 

What are the message digest algorithms supported in Java?

Here is a list of message digest algorithms that are mandatory for Java to support:

 

1.   MD5: This older algorithm is now considered insecure for critical use due to vulnerabilities. It generates a 128-bit digest.

2.   SHA-1: Similarly outdated for high-security applications because of susceptibility to attacks, this algorithm yields a 160-bit digest.

3.   SHA-256: Part of the SHA-2 family, this secure and commonly used algorithm produces a 256-bit digest.

 

Additionally, depending on the Java version and provider, the following algorithms might be supported:

 

1.   SHA-384: A more robust variant within the SHA-2 family, delivering a 384-bit digest.

2.   SHA-512: The most robust in the SHA-2 family, generating a 512-bit digest.

3.   SHA-3: This represents the newest generation of secure hash functions, offering multiple variants with varying sizes of digests.

 

Following program print all the supported message digest algorithms in your Java environment.

 

MessageDigestSupportedAlgos.java

package com.sample.app;

import java.security.Provider;
import java.security.Provider.Service;
import java.security.Security;
import java.util.Set;

public class MessageDigestSupportedAlgos {

	public static void main(String[] args) {
		try {
			Provider[] providers = Security.getProviders();
			for (Provider provider : providers) {
				Set<Service> services = provider.getServices();
				for (Service service : services) {
					if (service.getType().equalsIgnoreCase("MessageDigest")) {
						System.out.println(service.getAlgorithm());
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

Output

SHA-1
MD2
MD5
SHA-512/256
SHA3-512
SHA-256
SHA-384
SHA-512/224
SHA-512
SHA3-256
SHA-224
SHA3-384
SHA3-224

Following application calculates the digest of a file.

 

MessageDigestUtil.java

package com.sample.app.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class MessageDigestUtil {

	private static final int BUFFER_LENGTH = 1024;

	private MessageDigestUtil() {

	}

	public static byte[] getDigest(final String digestAlgorithm, final String filePath) throws IOException {

		try (final FileInputStream fis = new FileInputStream(filePath)) {
			return getDigest(digestAlgorithm, fis);
		}
	}

	public static byte[] getDigest(final String digestAlgorithm, final File file) throws IOException {

		try (final FileInputStream fis = new FileInputStream(file)) {
			return getDigest(digestAlgorithm, fis);
		}
	}

	public static byte[] getDigest(final String digestAlgorithm, final byte[] bytes) {
		final MessageDigest messageDigest = getMessageDigest(digestAlgorithm);
		messageDigest.update(bytes);
		return messageDigest.digest();
	}

	public static byte[] getDigest(final String digestAlgorithm, final InputStream inputStream) throws IOException {
		final MessageDigest messageDigest = getMessageDigest(digestAlgorithm);

		final byte[] buffer = new byte[BUFFER_LENGTH];
		int bytesRead = inputStream.read(buffer, 0, BUFFER_LENGTH);

		while (bytesRead > -1) {
			messageDigest.update(buffer);
			bytesRead = inputStream.read(buffer, 0, BUFFER_LENGTH);
		}

		return messageDigest.digest();
	}

	private static MessageDigest getMessageDigest(String digestAlgorithm) {
		try {
			return MessageDigest.getInstance(digestAlgorithm);
		} catch (final NoSuchAlgorithmException e) {
			throw new IllegalArgumentException(digestAlgorithm, e);
		}
	}
}

demo.png


FileDigest.java

package com.sample.app;

import java.io.IOException;
import java.util.Base64;

import com.sample.app.util.MessageDigestUtil;

public class FileDigest {

	public static void main(String[] args) throws IOException {
		String filePath = "/Users/Shared/demo.png";

		byte[] digestBytes = MessageDigestUtil.getDigest("SHA-256", filePath);
		Base64.Encoder encoder = Base64.getEncoder();
		String digest = new String(encoder.encode(digestBytes));
		System.out.println("digest : " + digest);
	}

}

Output

digest : ZuWbW5agWDi6X0cBmE64OFGQ0+KxD3rQ0f8OgG6FI70=


You may like

file and stream programs in Java

Convert InputStream to string

Write InputStream to a file in Java

File separator, separatorChar, pathSeparator, pathSeparatorChar in Java

Implement an Output stream that writes the data to two output streams

Check whether directory can be accessed and has read and write privileges in Java

No comments:

Post a Comment