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
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
Does Java Have a Int.Tryparse That Doesn't Throw an Exception for Bad Data
Default Fetch Type for One-To-One, Many-To-One and One-To-Many in Hibernate
Jackson Overcoming Underscores in Favor of Camel-Case
Java - How to Receive Point Coordinates After Mouse Button Release (Jfreechart)
When Are Java Strings Interned
Abstractmethoderror Using Uribuilder on Jax-Rs
Naming Convention for Getters/Setters in Java
Java: Setcellvaluefactory; Lambda VS. Propertyvaluefactory; Advantages/Disadvantages
The Split() Method in Java Does Not Work on a Dot (.)
Is It Safe to Get Values from a Java.Util.Hashmap from Multiple Threads (No Modification)
How to Launch Ie Browser Using Selenium2 (Webdriver) with Java
Is Polymorphism Possible Without Inheritance
Limiting Java Ssl Debug Logging
Using Java to Decrypt Openssl Aes-256-Cbc Using Provided Key and Iv
When to Use Atomicreference in Java