如何在Java中使用sha256对某些字符串进行哈希处理?


Answers:


308

SHA-256不是“编码”,而是单向哈希。

您基本上可以将字符串转换为字节(例如使用text.getBytes(StandardCharsets.UTF_8)),然后对字节进行哈希处理。请注意,哈希的结果将是任意二进制数据,并且如果要在字符串中表示它,则应使用base64或hex ... 不要尝试使用String(byte[], String)构造函数。

例如

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

18
“ SHA-256不是编码”绝对正确,但是我必须说,我更喜欢当前问题的标题,而不是“如何用sha加密”(许多人似乎认为这是加密)。也许我们应该将其视为编码而不是与加密相关的事情,因为在实践中,它更接近于使用方式。
2014年

5
@Luc:那么这是一个加密哈希,所以我不认为这是不合理的说,它确实有一些做与密码...加密和密码都没有互换...
乔恩斯基特

8
注意:最好使用StandardCharsets.UTF_8而不是"UTF-8"Java 7+ 中的原义:少担心一个检查异常。
kryger

3
在处理哈希结果时,为什么要避免使用String(byte [],String)构造函数?
艾萨克·范·巴克尔

5
@IsaacvanBakel:因为哈希不是编码文本。它是任意二进制数据。
乔恩·斯基特

172

我认为最简单的解决方案是使用Apache Common Codec

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

1
最佳答案,易于使用,清洁。谢谢!
fl0w

99

另一个选择是Guava,它具有易于使用的哈希实用程序套件。例如,要使用SHA256作为十六进制字符串来散列字符串,您只需执行以下操作:

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

85

完整示例散列为另一个字符串。

public static String sha256(String base) {
    try{
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(base.getBytes("UTF-8"));
        StringBuffer hexString = new StringBuffer();

        for (int i = 0; i < hash.length; i++) {
            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);
    }
}

7
要将Jon的结果编码为十六进制,请考虑使用现有的库(如apache commons),而不要自己滚动。
Leigh 2012年

1
为什么使用StringBuffer?(不是stringBuilder)?也许最好设置stringbuilder的默认大小?
博格丹

36
@Leigh:有些人不想只添加一个完整的lib依赖项,所以他们自己滚动有时是个好主意。
克里斯

4
@克里斯-是的。这就是为什么我说“考虑”使用它的原因;-)现有的库会增加容量。另一方面,它们通常比本地旋转代码经过更高的测试,当然可以节省时间。但是,没有一个适合所有人的“一刀切”的答案。
Leigh 2014年

1
您还可以从库中读取源代码并复制其代码!
OlavGrønåsGjerde,2016年

47

如果您使用的是Java 8,则可以byte[]通过

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

1
这样对我来说很方便。但是,您应该使用以下Base64.encodeToString(hash,Base64.DEFAULT);
Motassem Jalal

@MotassemJalal Base64.DEFAULT在Java8的最新版本中不可用,我当前正在使用jdk1.8.0_144,能否请您告诉我您是如何创建的?
rajadilipkolli

2
@rajadilipkolli我认为这是Android实施:developer.android.com/reference/android/util/Base64
dbm

12
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();
 }
}

用位按位对字节值的意义0xff何在?它什么都不产生,是吗?
yktoo

2
@yktoo:它将其转换为正整数(不幸的是,字节在Java中是带符号的)stackoverflow.com/questions/11380062/…–
leonbloy

StringBuffer可以替换为StringBuilder
User8461 '18

10
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;
}

7

我跟踪了Apache代码DigestUtilssha256似乎默认返回到java.security.MessageDigest进行计算。Apache没有实现独立的sha256解决方案。我一直在寻找一个独立的实现与java.security图书馆进行比较。仅供参考。


3

这是我使用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)})
}

嗨,我刚刚尝试了您的代码,因为我需要在Android Studio中对密码进行哈希处理,并且您的代码返回如下内容:[B@188363e,而不是加密的密码。另外,每次调用此函数似乎都不同。
Adrian2895

1
已修复,您忘记了return hash.fold("", { str, it -> str + "%02x".format(it)})返回加密密码而不返回对象本身的密码。
Adrian2895

1
是的,您是对的,让我用您的修复程序更新答案。谢谢您:)
塞缪尔·路易斯

2

这是将摘要转换为十六进制字符串的一种更有效的方法:

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);
}

有人知道Java中有更快的方法吗?


1

您可以通过以下方式使用MessageDigest:

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();
}

1

在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());

0

在Java中,MessageDigest类用于计算加密哈希值。此类提供密码哈希函数(MD5SHA-1SHA-256)以查找文本的哈希值。

使用SHA-256算法的代码示例。

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);

  }
}

0

这就是我用于哈希的内容:

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);

输出:5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8


-2
private static String getMessageDigest(String message, String algorithm) {
 MessageDigest digest;
 try {
  digest = MessageDigest.getInstance(algorithm);
  byte data[] = digest.digest(message.getBytes("UTF-8"));
  return convertByteArrayToHexString(data);
 } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
 }
 return null;
}

您可以使用以下类似的算法调用上述方法。

getMessageDigest(message, "MD5");
getMessageDigest(message, "SHA-256");
getMessageDigest(message, "SHA-1");

您可以参考此链接以获得完整的应用程序。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.