In Java, we can use MessageDigest
to get a SHA-256
or SHA3-256
hashing algorithm to hash a string.
MessageDigest md = MessageDigest.getInstance("SHA3-256");
byte[] result = md.digest(input);
This article shows how to use Java SHA-256
and SHA3-256
algorithms to generate a hash value from a given string and checksum from a file.
Note
The hashing is a one-way compression function to convert inputs of different lengths into a fixed-length output (hash value).
1. SHA-2 and SHA-3
1.1 The SHA-2 (Secure Hash Algorithm 2) is defined in FIPS PUB 180-4. The SHA-2 is a widely used hashing algorithm designed by the National Security Agency (NSA).
Java supports the following SHA-2
algorithms:
SHA-224
SHA-256
SHA-384
SHA-512
SHA-512/224
SHA-512/256
The SHA-256
produces a 256-bit output, 32 bytes, while SHA-512
produces a 512-bit output, 64 bytes.
String : Hello World
SHA-256
a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
SHA-512
2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b
1.2 The SHA-3 (Secure Hash Algorithm 3) is defined in FIPS PUB 202. The SHA-3 is the latest member of the Secure Hash Algorithms, released by National Institute of Standards and Technology (NIST).
Java supports the following SHA-3
algorithms:
SHA3-224
SHA3-256
SHA3-384
SHA3-512
String : Hello World
SHA3-256
e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51
SHA3-512
2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b
Futher Reading
- Read this What is the difference between SHA-3 and SHA-256?
- Read this Comparison of SHA functions
2. Java SHA3-256 Hashing
This Java example hashes a string with the SHA3-256
algorithm.
ShaUtils.java
package com.favtuts.crypto.hash; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class ShaUtils { private static final Charset UTF_8 = StandardCharsets.UTF_8; private static final String OUTPUT_FORMAT = "%-20s:%s"; public static byte[] digest(byte[] input, String algorithm) { MessageDigest md; try { md = MessageDigest.getInstance(algorithm); } catch (NoSuchAlgorithmException e) { throw new IllegalArgumentException(e); } byte[] result = md.digest(input); return result; } public static String bytesToHex(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) { //String algorithm = "SHA-256"; // if you perfer SHA-2 String algorithm = "SHA3-256"; String pText = "Hello World"; // String pText = "Hello SHA Hashing"; //Try hash another string, differ length, for SHA3-256, the output fixed to 256 bits, 32 bytes. System.out.println(String.format(OUTPUT_FORMAT, "Input (string)", pText)); System.out.println(String.format(OUTPUT_FORMAT, "Input (length)", pText.length())); byte[] shaInBytes = ShaUtils.digest(pText.getBytes(UTF_8), algorithm); System.out.println(String.format(OUTPUT_FORMAT, algorithm + " (hex) ", bytesToHex(shaInBytes))); // fixed length, 32 bytes, 256 bits. System.out.println(String.format(OUTPUT_FORMAT, algorithm + " (length)", shaInBytes.length)); } }
Output
Input (string) :Hello World
Input (length) :11
SHA3-256 (hex) :e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51
SHA3-256 (length) :32
Try hash another string, differ length, for SHA3-256
, the output fixed to 256 bits, 32 bytes.
Output
Input (string) :Hello SHA Hashing
Input (length) :17
SHA3-256 (hex) :72fbf4f3a807d344a1ee492ff4183edf72e45fab8dfa6a6e5447226233633bf8
SHA3-256 (length) :32
3. Java SHA3-256 File Checksum
A file in resources folder.
sha-file.txt
Hello World
This example uses the SHA3-256
algorithm to generate a checksum for the above file.
package com.favtuts.crypto.hash; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class ShaUtils { private static byte[] checksum(String filePath, String algorithm) { MessageDigest md; try { md = MessageDigest.getInstance(algorithm); } catch (NoSuchAlgorithmException e) { throw new IllegalArgumentException(e); } try (InputStream is = new FileInputStream(filePath); DigestInputStream dis = new DigestInputStream(is, md)) { while (dis.read() != -1) ; //empty loop to clear the data md = dis.getMessageDigest(); } catch (IOException e) { throw new IllegalArgumentException(e); } return md.digest(); } public static String bytesToHex(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) { String algorithm = "SHA3-256"; // get file path from resources String filePath = ClassLoader.getSystemResource("sha-file.txt").getFile(); byte[] hashInBytes = checksum(filePath, algorithm); System.out.println(bytesToHex(hashInBytes)); } }
Output
e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51
4. NoSuchAlgorithmException
Read this for all Java supported MessageDigest Algorithms. If we provide a non existed algorithm, for example, SHA4-256
, Java throws java.security.NoSuchAlgorithmException
.
MessageDigest md = MessageDigest.getInstance("SHA4-256");
java.security.NoSuchAlgorithmException: SHA4-256 MessageDigest not available
at com.mkyong.crypto.hash.ShaUtils.digest(ShaUtils.java:22)
at com.mkyong.crypto.hash.ShaUtils.main(ShaUtils.java:65)
Caused by: java.security.NoSuchAlgorithmException: SHA4-256 MessageDigest not available
at java.base/sun.security.jca.GetInstance.getInstance(GetInstance.java:159)
at java.base/java.security.Security.getImpl(Security.java:700)
at java.base/java.security.MessageDigest.getInstance(MessageDigest.java:178)
at com.favtuts.crypto.hash.ShaUtils.digest(ShaUtils.java:20)
... 1 more
5. Apache Commons Codec
This example uses the popular Apache Commons Codec to hash a string with the SHA algorithms.
pom.xml
<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.14</version> </dependency>
import org.apache.commons.codec.digest.DigestUtils; // SHA-2 byte[] hash1 = DigestUtils.sha256(""); // returns byte arrays String hash2 = DigestUtils.sha256Hex(""); // returns encoded hex // SHA-3 byte[] hash3 = DigestUtils.sha3_256(""); // returns byte arrays String hash4 = DigestUtils.sha3_256Hex(""); // returns encoded hex
6. Add Salt to SHA hashing
The salt is a random data, a technique to prevent rainbow attacks. In Java, we can use SecureRandom
to generate a salt (random bytes).
public static byte[] getRandomNonce(int numBytes) { byte[] nonce = new byte[numBytes]; new SecureRandom().nextBytes(nonce); return nonce; }
This example generates a random 16 bytes salt and uses ByteBuffer
to prefix it to a string. In the end, we use the SHA3-256
algorithm to generate a hash value from the salt + string
.
// get a 16 bytes random salt. byte[] salt = CryptoUtils.getRandomNonce(16); byte[] pText = "Hello World".getBytes(StandardCharsets.UTF_8); // combine two byte arrays byte[] input = ByteBuffer.allocate(salt.length + pText.length) .put(salt) .put(pText) .array(); // no salt, SHA3-256 System.out.println(bytesToHex(ShaUtils.digest(pText, "SHA3-256"))); // 16 bytes salt, SHA3-256 System.out.println(bytesToHex(ShaUtils.digest(input, "SHA3-256")));
Output
# no salt
e167f68d6563d75bb25f3aa49c29ef612d41352dc00606de7cbd630bb2665f51
# 16 bytes salt
a6c589937ea475fc942d31d154d359ff569ff99fa32ee5d996ff64eca2e7551b
Download Source Code
$ git clone https://github.com/favtuts/java-core-tutorials-examples
$ cd java-crypto