Hash String via Sha-256 in Java

How to hash some String with SHA-256 in Java?

SHA-256 isn't an "encoding" - it's a one-way hash.

You'd basically convert the string into bytes (e.g. using text.getBytes(StandardCharsets.UTF_8)) and then hash the bytes. Note that the result of the hash would also be arbitrary binary data, and if you want to represent that in a string, you should use base64 or hex... don't try to use the String(byte[], String) constructor.

e.g.

MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));

Hash String via SHA-256 in Java

To hash a string, use the built-in MessageDigest class:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
import java.math.BigInteger;

public class CryptoHash {
public static void main(String[] args) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
String text = "Text to hash, cryptographically.";

// Change this to UTF-16 if needed
md.update(text.getBytes(StandardCharsets.UTF_8));
byte[] digest = md.digest();

String hex = String.format("%064x", new BigInteger(1, digest));
System.out.println(hex);
}
}

In the snippet above, digest contains the hashed string and hex contains a hexadecimal ASCII string with left zero padding.

Verify Hashing.sha256() generated hash

SHA-256 and, in general, the family of SHA 2 algorithms is wonderfully described in Wikipedia and different RFCs, RFC 6234 and the superseded RFC 4634.

All these sources dictate that the output provided by the SHA 256 hash function is 256 bits length, 32 bytes (the number that accompanies the SHA word is the mentioned value for every algorithm in the family, roughly speaking).

These sequence of bytes is typically encoded in hex. This is the implementation provided by Guava as well.

Then, the problem can be reduced to identify if a string in Java is a valid hex encoding.

That problem has been already answered here, in SO, for example in this question.

For its simplicity, consider the solution proposed by @laycat:

boolean isHex = mac_addr.matches("^[0-9a-fA-F]+$");

As every byte is encoded with two hex characters and, as mentioned, the SHA-256 algorithm produces and output of 32 bytes you can safely check for a string of 64 characters length, as suggested in the answer of @D.O. as well. Your validation code could be similar to this:

boolean canBeSha256Output = sha256Hex.matches("^[0-9a-fA-F]{64}$");

Please, be aware that there is no possibility for saying if a character hex string of a certain length on its own is or not the result of a hash function, whichever hash function you consider.

You only can be sure that a hash output is a hash output if and only if it matches the result of applying the corresponding hash function over the original input.

Hashing password by SHA256 then write to file

Code

You can test/run this code on ▶▶▶▶▶ https://replit.com/@JomaCorpFX/JavaHashes

HashAlgorithm.java

public enum HashAlgorithm {

SHA512("SHA-512"),
SHA256("SHA-256"),
SHA384("SHA-384"),
SHA1("SHA-1"),
MD5("MD5");

private String Value = "";

HashAlgorithm(String Value) {
this.Value = Value;
}

@Override
public String toString() {
return Value;
}

}

HexEncoder.java

import java.util.Formatter;

public class HexEncoder{
public static String toHex(byte[] data) {
StringBuilder sb = new StringBuilder(data.length * 2);
try (Formatter formatter = new Formatter(sb))
{
for (byte b : data)
{
formatter.format("%02x", b);
}
}
return sb.toString();
}
}

HashManager.java

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

public class HashManager {
public static byte[] toRawHash(byte[] data, HashAlgorithm algorithm) throws Exception
{
byte[] buffer = data;
MessageDigest messageDigest = MessageDigest.getInstance(algorithm.toString());
messageDigest.reset();
messageDigest.update(buffer);
return messageDigest.digest();
}

public static String toHexHash(byte[] data, HashAlgorithm algorithm) throws Exception
{
return HexEncoder.toHex(toRawHash(data, algorithm));
}

public static String toHexHash(String data, HashAlgorithm algorithm) throws Exception
{
return toHexHash(data.getBytes(StandardCharsets.UTF_8), algorithm);
}
}

Main.java

public class Main {
public static void main(String[] args) throws Exception {
String data = "grape";
System.out.println(HashManager.toHexHash(data, HashAlgorithm.SHA256));
System.out.println(HashManager.toHexHash(data, HashAlgorithm.SHA256));
System.out.println(HashManager.toHexHash(data, HashAlgorithm.SHA256));
System.out.println(HashManager.toHexHash(data, HashAlgorithm.SHA256));

}
}

Output

output1

Hash a hexadecimal number using SHA-256 in java

Without using BigInteger:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;

public class HashIt {

public static void main(String[] args) throws NoSuchAlgorithmException {
byte[] input = new byte[] { (byte) 0xf3, (byte) 0x5b };
System.out.println(toHexString(input));

MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(input);
byte[] hashedXArray = md.digest();

System.out.println(toHexString(hashedXArray));
}

private static String toHexString(byte[] bytes) {
Formatter result = new Formatter();
try (result) {
for (var b : bytes) {
result.format("%02x", b & 0xff);
}
return result.toString();
}
}
}

Output:

f35b

cd05094b5c5a5b80386da4fcfdd20e6ef5d363d97834ac8705e9832e6bd97f39


If input must be string, add:

    private static byte[] fromHexString(String text) {
assert text.length()%2 == 0 : "invalid text length";

byte[] result = new byte[text.length()/2];
for (int i = 0; i < text.length(); i += 2) {
result[i/2] = (byte) Integer.parseInt(text.substring(i, i+2), 16);
}
return result;
}

and call as byte[] input = fromHexString("f35b");

just one solution of many


One reason not to use BigInteger:

BigInteger x = new BigInteger("00001234", 16);
byte[] input = x.toByteArray();
System.out.println(Arrays.toString(input));

leading zeros are removed, results in

[18, 52]

or

BigInteger x = new BigInteger("FFFF", 16);
byte[] input = x.toByteArray();
System.out.println(Arrays.toString(input));

additional zero is added (make it positive):

[0, -1, -1]


Why getting wrong results:

BigInteger x = new BigInteger("f35b", 16);
System.out.println(Integer.toHexString(x.byteValue()));

results in 5b, that is, the low byte of given BigInteger.

How do I generate a hash code with hash sha256 in java?

I'm still unclear whether you want SHA-1 or SHA-256, so let's abstract the problem; firstly, an encode method to take a byte[] and return the hex (don't worry, you already wrote it; but I would prefer a StringBuilder over String concatenation. Java String is immutable, so you're creating garbage for later garbage collection with +) -

private static String encodeHex(byte[] digest) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
sb.append(Integer.toString((digest[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}

Next, we can create a method that takes the algorithm name and the String to digest and returns that digest. Like

public static String digest(String alg, String input) {
try {
MessageDigest md = MessageDigest.getInstance(alg);
byte[] buffer = input.getBytes("UTF-8");
md.update(buffer);
byte[] digest = md.digest();
return encodeHex(digest);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
e.printStackTrace();
return e.getMessage();
}
}

Then we can get a SHA-1 or a SHA-256 hash like

public static void main(String[] args) {
System.out.println(digest("SHA1", ""));
System.out.println(digest("SHA-256", ""));
}

Which outputs (as expected)

da39a3ee5e6b4b0d3255bfef95601890afd80709
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Java SHA-256 Program provides wrong Hash

A 32-byte hash means a string of 64 characters. Each byte contains 2 hex digits, so you need 2 characters per byte:

while (hexString.length() < 64)  
{
hexString.insert(0, '0');
}


Related Topics



Leave a reply



Submit