316

How can I hash some String with SHA-256 in Java?

2

17 Answers 17

394

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));
Sign up to request clarification or add additional context in comments.

10 Comments

"SHA-256 isn't an encoding" absolutely right, but I must say I prefer the current question's title to "how to encrypt with sha" (many seem to think it's encryption). Perhaps we should treat it as encoding instead of something to do with cryptography because in practice that's closer to how it's used.
@Luc: Well it's a cryptographic hash, so I don't think it's unreasonable to say it does have something to do with cryptography... encryption and cryptography aren't interchangable...
Note: it's a good idea to use StandardCharsets.UTF_8 instead of the "UTF-8" literal in Java 7+: one checked exception less to worry about.
Why should you avoid the String(byte[], String) constructor when dealing with the hash result?
@IsaacvanBakel: Because a hash isn't encoded text. It's arbitrary binary data.
|
244

I think that the easiest solution is to use Apache Common Codec:

String sha256hex = org.apache.commons.codec.digest.DigestUtils.sha256Hex(stringText);   

Comments

117

Full example hash to string as another string.

public static String sha256(final String base) {
    try{
        final MessageDigest digest = MessageDigest.getInstance("SHA-256");
        final byte[] hash = digest.digest(base.getBytes("UTF-8"));
        final StringBuilder hexString = new StringBuilder();
        for (int i = 0; i < hash.length; i++) {
            final String hex = Integer.toHexString(0xff & hash[i]);
            if(hex.length() == 1) 
              hexString.append('0');
            hexString.append(hex);
        }
        return hexString.toString();
    } catch(Exception ex){
       throw new RuntimeException(ex);
    }
}

8 Comments

To encode Jon's results as hex, consider using an existing library like apache commons rather than rolling your own.
Why StringBuffer? (not a stringBuilder)? and maybe it would be better to set default size of stringbuilder?
@Leigh: some people dont want to add a whole lib dependency just because they need a single function of it so rolling your own is sometimes a good idea.
@Chris - True. That is why I said "consider" using it ;-) Existing libs can add bulk. On the flip side they are usually more highly tested than home spun code and of course save time. But there is no one-size-fits-all answer for everyone.
You could also read the source code from the library and copy its code!
|
116

Another alternative is Guava which has an easy-to-use suite of Hashing utilities. For example, to hash a string using SHA256 as a hex-string you would simply do:

final String hashed = Hashing.sha256()
        .hashString("your input", StandardCharsets.UTF_8)
        .toString();

1 Comment

Just to note – since introduction in version 11 it still marked as @Beta in version 30.
67

If you are using Java 8 you can encode the byte[] by doing

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

6 Comments

This way is convenient for me. However, you should use the following Base64.encodeToString(hash, Base64.DEFAULT);
@MotassemJalal Base64.DEFAULT is not available in latest version of Java8, I am currently using jdk1.8.0_144, Can you please tell me how you have created it?
@rajadilipkolli I think it's the Android implementation: developer.android.com/reference/android/util/Base64
For some reason I get the wrong result from this. Example: for the input of "test", I got n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg= instead of 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 . How come?
It is one way of doing it, but not the common standard. @android developer, that is why you are seeing a different value here than what you'd see in other implementations.
|
15
import java.security.MessageDigest;

public class CodeSnippets {

 public static String getSha256(String value) {
    try{
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(value.getBytes());
        return bytesToHex(md.digest());
    } catch(Exception ex){
        throw new RuntimeException(ex);
    }
 }
 private static String bytesToHex(byte[] bytes) {
    StringBuffer result = new StringBuffer();
    for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
    return result.toString();
 }
}

3 Comments

What's the point of bitwise &-ing a byte value with 0xff? It yields nothing, does it?
@yktoo : It converts it to a positive integer (bytes are signed in Java, unfortunately) stackoverflow.com/questions/11380062/…
StringBuffer can replaced by a StringBuilder
12
String hashWith256(String textToHash) {
    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    byte[] byteOfTextToHash = textToHash.getBytes(StandardCharsets.UTF_8);
    byte[] hashedByetArray = digest.digest(byteOfTextToHash);
    String encoded = Base64.getEncoder().encodeToString(hashedByetArray);
    return encoded;
}

Comments

10

This method return a left padded String with zero:

Java 10 and after:

public static String sha256(String text) {
    try {
        var messageDigest = MessageDigest.getInstance("SHA-256");
        var hash = messageDigest.digest(text.getBytes(StandardCharsets.UTF_8));
        
        return String.format("%064x", new BigInteger(1, hash));
    }
    catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
}

Java 8:

public static String sha256(String text) {
    try {
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
        byte[] hash = messageDigest.digest(text.getBytes(StandardCharsets.UTF_8));
        
        return String.format("%064x", new BigInteger(1, hash));
    }
    catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
}

BTW, you can use "%064X" for an uppercase result.

Example:

System.out.println(sha256("hello world 1"));

063dbf1d36387944a5f0ace625b4d3ee36b2daefd8bdaee5ede723637efb1cf4

Comparison to Linux cmd:

$ echo -n 'hello world 1' | sha256sum 063dbf1d36387944a5f0ace625b4d3ee36b2daefd8bdaee5ede723637efb1cf4 -

Comments

9

I traced the Apache code through DigestUtils and sha256 seems to default back to java.security.MessageDigest for calculation. Apache does not implement an independent sha256 solution. I was looking for an independent implementation to compare against the java.security library. FYI only.

Comments

6

In Java 8

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
import javax.xml.bind.DatatypeConverter;


Scanner scanner = new Scanner(System.in);
String password = scanner.nextLine();
scanner.close();

MessageDigest digest = null;
try {
    digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
byte[] hash = digest.digest(password.getBytes(StandardCharsets.UTF_8));
String encoded = DatatypeConverter.printHexBinary(hash);        
System.out.println(encoded.toLowerCase());

1 Comment

Why do you have this try/catch in such way?
5

Here is a slightly more performant way to turn the digest into a hex string:

private static final char[] hexArray = "0123456789abcdef".toCharArray();

public static String getSHA256(String data) {
    StringBuilder sb = new StringBuilder();
    try {
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(data.getBytes());
        byte[] byteData = md.digest();
        sb.append(bytesToHex(byteData);
    } catch(Exception e) {
        e.printStackTrace();
    }
    return sb.toString();
}

private static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    for ( int j = 0; j < bytes.length; j++ ) {
        int v = bytes[j] & 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return String.valueOf(hexChars);
}

Does anyone know of a faster way in Java?

Comments

5

This is what i have been used for hashing:

String pass = "password";

MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
byte hashBytes[] = messageDigest.digest(pass.getBytes(StandardCharsets.UTF_8));
BigInteger noHash = new BigInteger(1, hashBytes);
String hashStr = noHash.toString(16);

Output: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8

Comments

4

This was my approach using Kotlin:

private fun getHashFromEmailString(email : String) : String{
    val charset = Charsets.UTF_8
    val byteArray = email.toByteArray(charset)
    val digest = MessageDigest.getInstance("SHA-256")
    val hash = digest.digest(byteArray)

    return hash.fold("", { str, it -> str + "%02x".format(it)})
}

3 Comments

Hi, I have just tried your code because I need to hash a password in Android Studio and your code returns something like this: [B@188363e, not the encrypted password. Plus, it seems to be different each time this function is called.
Fixed, you forgot return hash.fold("", { str, it -> str + "%02x".format(it)}) which returns the encrypted password and not the object itself.
yes you're right, let me update the answer with your fix. Thank you :)
1

You can use MessageDigest in the following way:

public static String getSHA256(String data){
    StringBuffer sb = new StringBuffer();
    try{
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(data.getBytes());
        byte byteData[] = md.digest();

        for (int i = 0; i < byteData.length; i++) {
         sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
        }
    } catch(Exception e){
        e.printStackTrace();
    }
    return sb.toString();
}

Comments

1
public static String sha256(String s) {
    try {
        return DatatypeConverter.printHexBinary(MessageDigest.getInstance("SHA-256").digest(s.getBytes(StandardCharsets.UTF_8))).toLowerCase();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    return null;
}

2 Comments

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
Where does DatatypeConverter comes from?
0

In Java, MessageDigest class is used to calculate cryptographic hashing value. This class provides cryptographic hash function ( MD5, SHA-1 and SHA-256) to find hash value of text.

Code example for using SHA-256 algorithm.

public void printHash(String str) throws NoSuchAlgorithmException {

MessageDigest md=MessageDigest.getInstance("SHA-256");

byte[] sha256=md.digest(str.getBytes(StandardCharsets.UTF_8));

   for(byte b : sha256){

      System.out.printf("%02x",b);

  }
}

Comments

-1

Here's a method that shows how to hash a String with the sha-256 algorithm and encode the result in hex format. This is an often used format to hash and store passwords in a database:

public static String sha256(final String data) {
    try {
        final byte[] hash = MessageDigest.getInstance("SHA-256").digest(data.getBytes(StandardCharsets.UTF_8));
        final StringBuilder hashStr = new StringBuilder(hash.length);

        for (byte hashByte : hash)
            hashStr.append(Integer.toHexString(255 & hashByte));

        return hashStr.toString();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
        return null;
    }
}

2 Comments

Some cases using this approach generates the wrong hash. Try hashing the "abcd" string. The expected is: 88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589 ; but it generates 88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f31589 ; missing one zero
This piece of code provided as answer is wrong and should be edited or removed. When it converts the hash to Hex, it removes leading/repeating zeros, creating a wrong hash.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.