Làm thế nào để băm một số chuỗi với sha256 trong Java?


Câu trả lời:


307

SHA-256 không phải là "mã hóa" - đó là hàm băm một chiều.

Về cơ bản, bạn sẽ chuyển đổi chuỗi thành byte (ví dụ: sử dụng text.getBytes(StandardCharsets.UTF_8)) và sau đó băm các byte. Lưu ý rằng kết quả của hàm băm cũng sẽ là dữ liệu nhị phân tùy ý và nếu bạn muốn biểu diễn chuỗi đó trong chuỗi, bạn nên sử dụng base64 hoặc hex ... đừng cố sử dụng hàm String(byte[], String)tạo.

ví dụ

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

18
"SHA-256 không phải là mã hóa" hoàn toàn đúng, nhưng tôi phải nói rằng tôi thích tiêu đề của câu hỏi hiện tại hơn là "cách mã hóa bằng sha" (nhiều người nghĩ rằng đó là mã hóa). Có lẽ chúng ta nên coi nó như mã hóa thay vì liên quan đến mật mã bởi vì trong thực tế, nó gần với cách sử dụng nó hơn.
Luc

5
@Luc: Vâng đó là một băm mật mã, vì vậy tôi không nghĩ rằng đó là không hợp lý để nói nó không có cái gì để làm với mật mã ... mã hóa và mật mã không hoán đổi cho nhau ...
Jon Skeet

8
Lưu ý: nên sử dụng StandardCharsets.UTF_8 thay vì "UTF-8"nghĩa đen trong Java 7+: một ngoại lệ được kiểm tra ít phải lo lắng hơn.
kryger

3
Tại sao bạn nên tránh hàm tạo Chuỗi (byte [], Chuỗi) khi xử lý kết quả băm?
Isaac van Bakel

5
@IsaacvanBakel: Vì hàm băm không được mã hóa văn bản. Đó là dữ liệu nhị phân tùy ý.
Jon Skeet

172

Tôi nghĩ rằng giải pháp đơn giản nhất là sử dụng Apache Common Codec :

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

1
Câu trả lời tốt nhất, dễ sử dụng, sạch sẽ. Cảm ơn bạn!
fl0w

99

Một lựa chọn khác là Guava có bộ tiện ích Hashing dễ sử dụng . Ví dụ: để băm một chuỗi bằng SHA256 dưới dạng chuỗi hex bạn chỉ cần làm:

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

85

Ví dụ đầy đủ băm để chuỗi như một chuỗi khác.

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
Để mã hóa kết quả của Jon dưới dạng hex, hãy xem xét sử dụng một thư viện hiện có như apache commons thay vì tự cuộn.
Leigh

1
Tại sao StringBuffer? (không phải là một StringBuilder)? và có lẽ sẽ tốt hơn nếu đặt kích thước mặc định của Stringbuilder?
Bogdan

36
@Leigh: một số người không muốn thêm toàn bộ phụ thuộc lib chỉ vì họ cần một chức năng duy nhất của nó vì vậy việc tự mình thực hiện đôi khi là một ý tưởng hay.
Chris

4
@Chris - Đúng. Đó là lý do tại sao tôi nói "xem xét" bằng cách sử dụng nó ;-) Các lib hiện có có thể thêm số lượng lớn. Mặt khác, chúng thường được thử nghiệm cao hơn mã quay vòng tại nhà và tất nhiên tiết kiệm thời gian. Nhưng không có câu trả lời nào phù hợp cho tất cả mọi người.
Leigh

1
Bạn cũng có thể đọc mã nguồn từ thư viện và sao chép mã của nó!
Olav Grønås Gjerde

47

Nếu bạn đang sử dụng Java 8, bạn có thể mã hóa byte[]bằng cách thực hiện

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

1
Cách này là thuận tiện cho tôi. Tuy nhiên, bạn nên sử dụng Base64.encodeToString sau (hash, Base64.DEFAULT);
Motassem Jalal

@MotassemJalal Base64.DEFAULT không có sẵn trong phiên bản Java8 mới nhất, tôi hiện đang sử dụng jdk1.8.0_144, bạn có thể cho tôi biết bạn đã tạo ra nó như thế nào không?
rajadilipkolli

2
@rajadilipkolli Tôi nghĩ đó là triển khai 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();
 }
}

Điểm của bitwise & -ing một giá trị byte là 0xffgì? Nó không mang lại điều gì, phải không?
yktoo

2
@yktoo: Thật không may, nó chuyển đổi nó thành một số nguyên dương (không may là byte được ký bằng Java) stackoverflow.com/questions/11380062/
Kẻ

StringBuffer có thể được thay thế bằng StringBuilder
User8461

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

Tôi đã lần theo mã Apache DigestUtilssha256dường như mặc định quay lại để java.security.MessageDigesttính toán. Apache không thực hiện một sha256giải pháp độc lập . Tôi đang tìm kiếm một triển khai độc lập để so sánh với java.securitythư viện. Chỉ có FYI.


3

Đây là cách tiếp cận của tôi bằng cách sử dụng 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)})
}

Xin chào, tôi vừa thử mã của bạn vì tôi cần băm mật khẩu trong Android Studio và mã của bạn trả về một cái gì đó như thế này:, [B@188363ekhông phải mật khẩu được mã hóa. Thêm vào đó, nó dường như khác nhau mỗi khi chức năng này được gọi.
Adrian2895

1
Đã sửa lỗi, bạn quên mất return hash.fold("", { str, it -> str + "%02x".format(it)})mật khẩu được mã hóa và không phải chính đối tượng.
Adrian2895

1
vâng bạn đúng, hãy để tôi cập nhật câu trả lời với cách khắc phục của bạn. Cảm ơn bạn :)
Samuel Luís

2

Đây là một cách hiệu quả hơn một chút để biến digest thành chuỗi hex:

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

Có ai biết một cách nhanh hơn trong Java?


1

Bạn có thể sử dụng MessageDigest theo cách sau:

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

Trong 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

Trong Java, lớp MessageDigest được sử dụng để tính giá trị băm mật mã. Lớp này cung cấp hàm băm mật mã ( MD5 , SHA-1SHA-256 ) để tìm giá trị băm của văn bản.

Ví dụ mã để sử dụng thuật toán 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

Đây là những gì tôi đã được sử dụng để băm:

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

Đầu ra: 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;
}

Bạn có thể gọi phương thức trên với các thuật toán khác nhau như dưới đây.

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

Bạn có thể tham khảo liên kết này cho ứng dụng hoàn chỉnh.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.