String Java ke SHA1


158

Saya mencoba membuat konverter String to SHA1 sederhana di Java dan ini yang saya dapatkan ...

public static String toSHA1(byte[] convertme) {
    MessageDigest md = null;
    try {
        md = MessageDigest.getInstance("SHA-1");
    }
    catch(NoSuchAlgorithmException e) {
        e.printStackTrace();
    } 
    return new String(md.digest(convertme));
}

Ketika saya lulus toSHA1("password".getBytes()), saya [�a�ɹ??�%l�3~��.tahu saya mungkin memperbaiki encoding sederhana seperti UTF-8, tetapi bisakah seseorang memberi tahu saya apa yang harus saya lakukan untuk mendapatkan apa yang saya inginkan 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8? Atau apakah saya melakukan ini sepenuhnya salah?


Algoritma SHA1tanpa tanda hubung, tidak tahu apakah itu akan membuat perbedaan.
The Scrum Meister

Ini praktik yang baik untuk menentukan pengkodean karakter saat Anda menelepon getBytes(), misalnya gunakantoSHA1("password".getBytes("UTF-8"))
Qwerky

Jawaban:


183

PEMBARUAN
Anda dapat menggunakan Apache Commons Codec (versi 1.7+) untuk melakukan pekerjaan ini untuk Anda.

DigestUtils.sha1Hex (stringToConvertToSHexRepresentation)

Terima kasih kepada @ Jon Onstott untuk saran ini.


Jawaban Lama
Konversi Byte Array Anda ke Hex String. Cara Nyata memberitahu Anda caranya .

return byteArrayToHexString(md.digest(convertme))

dan (disalin dari Real's How To)

public static String byteArrayToHexString(byte[] b) {
  String result = "";
  for (int i=0; i < b.length; i++) {
    result +=
          Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
  }
  return result;
}

BTW, Anda bisa mendapatkan representasi yang lebih kompak menggunakan Base64. Apache Commons Codec API 1.4 , memiliki utilitas yang bagus untuk menghilangkan semua rasa sakit. lihat disini


4
base64 dan sha1 sangat berbeda - jangan menyarankan mereka sebagai alternatif.
Ryan A.

13
@RyanA .: Seperti yang saya pahami, ia menyarankan base64 sebagai alternatif untuk hex-encoding hash SHA1 (bukan sebagai alternatif untuk SHA1 sepenuhnya).
helmbert

Saya belum mencobanya, tetapi apakah Anda mau menjelaskan cara kerjanya?
Jivay

11
Mengapa tidak menggunakan perpustakaan seperti DigestUtils.sha1Hex("my string")alih - alih menciptakan kembali roda (meskipun menarik mengetahui cara mengonversi ke hex dengan tangan)?
Jon Onstott

3
Karena ketika jawaban ini ditulis DigestUtils (1,7 dirilis pada Sep 2012) tidak memiliki fitur itu. Terima kasih telah menunjukkan ini. +1
Nishant

67

Ini adalah solusi saya untuk mengubah string menjadi sha1. Ini bekerja dengan baik di aplikasi Android saya:

private static String encryptPassword(String password)
{
    String sha1 = "";
    try
    {
        MessageDigest crypt = MessageDigest.getInstance("SHA-1");
        crypt.reset();
        crypt.update(password.getBytes("UTF-8"));
        sha1 = byteToHex(crypt.digest());
    }
    catch(NoSuchAlgorithmException e)
    {
        e.printStackTrace();
    }
    catch(UnsupportedEncodingException e)
    {
        e.printStackTrace();
    }
    return sha1;
}

private static String byteToHex(final byte[] hash)
{
    Formatter formatter = new Formatter();
    for (byte b : hash)
    {
        formatter.format("%02x", b);
    }
    String result = formatter.toString();
    formatter.close();
    return result;
}

7
Mungkin ingin menentukan bahwa ini adalah java.util.Formatter dan membutuhkan formatter.close () di akhir untuk menghindari peringatan.
Eric Chen

Bukankah encryptPassword("test")dan echo test|sha1sumdi terminal linux menghasilkan hasil yang sama? Mereka tidak melakukannya.
Tulains Córdova

@ TulainsCórdova Mengenai permintaan konsol: Jika Anda menggunakan echo test, output termasuk jeda baris akan disalurkan ke sha1sum. Jika Anda ingin meng-hash string biasa tanpa mengekstrak line break, Anda bisa menggunakannya echo -n test | sha1sum. The -nparameter membuat echomenghilangkan garis istirahat.
MrSnrub

Lebih sedikit pertanyaan, tetapi lebih umum: encryptPassword()Suara Anda seperti itu digunakan untuk menyimpan data otentikasi. Perhatikan bahwa pengkodean Anda rentan terhadap serangan kamus, karena tidak ada seeding yang diterapkan. Periksa lingkungan keamanan Anda apakah ini merupakan masalah untuk aplikasi Anda!
EagleRainbow

54

Menggunakan kelas Jambu Hashing :

Hashing.sha1().hashString( "password", Charsets.UTF_8 ).toString()

1
Jawaban ini mungkin memerlukan pembaruan karena sekarang ini akan menghasilkan peringatan bahwa Hashing tidak stabil.
Semir Delji

32

SHA-1 (dan semua algoritma hashing lainnya) mengembalikan data biner. Itu berarti (di Jawa) mereka menghasilkan a byte[]. Itu bytearray yang tidak tidak mewakili karakter tertentu, yang berarti Anda tidak bisa hanya mengubahnya menjadi Stringseperti yang Anda lakukan.

Jika Anda memerlukan String, maka Anda harus memformatnya byte[]dengan cara yang dapat direpresentasikan sebagai String(jika tidak, simpan saja byte[]).

Dua cara umum untuk mewakili byte[]karakter sewenang - wenang sebagai karakter yang dapat dicetak adalah BASE64 atau hex-Strings sederhana (yaitu masing-masing mewakili bytedua digit heksadesimal). Sepertinya Anda mencoba menghasilkan hex-String.

Ada juga jebakan lain: jika Anda ingin mendapatkan SHA-1 dari Java String, maka Anda perlu mengubahnya Stringmenjadi yang byte[]pertama (karena input dari SHA-1 byte[]juga). Jika Anda hanya menggunakan myString.getBytes()seperti yang Anda tunjukkan, maka itu akan menggunakan pengkodean default platform dan karenanya akan bergantung pada lingkungan tempat Anda menjalankannya (misalnya, itu bisa mengembalikan data yang berbeda berdasarkan pengaturan bahasa / lokal OS Anda).

Sebuah solusi yang lebih baik adalah untuk menetapkan pengkodean untuk digunakan untuk String-to- byte[]konversi seperti ini: myString.getBytes("UTF-8"). Memilih UTF-8 (atau penyandian lain yang dapat mewakili setiap karakter Unicode) adalah pilihan paling aman di sini.


27

Ini adalah solusi sederhana yang dapat digunakan saat mengonversi string ke format hex:

private static String encryptPassword(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {

    MessageDigest crypt = MessageDigest.getInstance("SHA-1");
    crypt.reset();
    crypt.update(password.getBytes("UTF-8"));

    return new BigInteger(1, crypt.digest()).toString(16);
}

Peringatan: Pembuatan hash salah untuk hash yang dimulai dengan '0'. Anda akan menerima sebuah String dengan 39 karakter.
philn

@ philn, bisakah Anda menyarankan solusi?
Nikita Koksharov

1
Saya kira jika Anda membuat bilangan bulat besar dari byte [] dengan nol di depan yang cukup, 0s ini akan hilang. Dengan demikian, representasi string hex "0" tidak akan ada di sana, mengarah ke hash dengan 39 karakter atau kurang. Saya menggunakan solusi petrnohejls di atas dan berfungsi dengan baik ...
philn

25

Cukup gunakan pustaka codec apache commons. Mereka memiliki kelas utilitas yang disebut DigestUtils

Tidak perlu masuk ke detail.


51
Saya tidak setuju, masuk ke detail adalah semacam titik keseluruhan
ninesided

12
Pertanyaannya adalah apakah Anda punya waktu untuk masuk ke detail atau tidak. Intinya adalah menyelesaikannya tepat waktu. Tidak semua orang adalah mahasiswa atau memiliki kemewahan untuk mempelajari semua detail.
DaTroop

DigestUtils mengembalikan array byte sehingga untuk mendapatkan representasi string Anda perlu menjalankannya melalui Hex.encodeHexString. Java: ini 2014 dan kami masih belum memiliki metode satu langkah sha
ryber

5
Satu langkah metode SHA-1:; String result = DigestUtils.sha1Hex("An input string")o)
Jon Onstott

18

Seperti yang disebutkan sebelumnya gunakan apache commons codec. Ini direkomendasikan oleh Spring guys juga (lihat DigestUtils di Spring doc). Misalnya:

DigestUtils.sha1Hex(b);

Jelas tidak akan menggunakan jawaban berperingkat teratas di sini.


7

Ini tidak mencetak dengan benar karena Anda harus menggunakan pengkodean Base64. Dengan Java 8 Anda dapat menyandikan menggunakan kelas encoder Base64 .

public static String toSHA1(byte[] convertme) {
    md = MessageDigest.getInstance("SHA-1");
    return Base64.getEncoder().encodeToString((md.digest(convertme));
}

Hasil

Ini akan memberi Anda hasil yang diharapkan dari 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8


1
@Devenv itu SHA-1 tiga titik berarti akan mempertahankan kode aslinya yang dikonversi ke sha1. Masalah asli OP adalah ketika mencetak string dengan benar.
Eduardo Dennis

4

Pesan Intisari (hash) adalah byte [] dalam byte [] keluar

Intisari pesan didefinisikan sebagai fungsi yang mengambil array byte mentah dan mengembalikan array byte mentah (alias byte[]). Misalnya SHA-1 (Secure Hash Algorithm 1) memiliki ukuran digest 160 bit atau 20 byte. Array byte mentah biasanya tidak dapat diartikan sebagai pengkodean karakter seperti UTF-8 , karena tidak setiap byte dalam setiap order adalah legal yang encoding. Jadi mengubahnya menjadi String:

new String(md.digest(subject), StandardCharsets.UTF_8)

mungkin membuat beberapa urutan ilegal atau memiliki penunjuk kode ke pemetaan Unicode yang tidak terdefinisi :

[�a�ɹ??�%l3~��.

Encoding biner-ke-teks

Untuk itu digunakan pengkodean biner-ke-teks . Dengan hash, yang paling banyak digunakan adalah penyandian HEX atau Base16 . Pada dasarnya satu byte dapat memiliki nilai dari 0ke 255(atau -128ke 127ditandatangani) yang setara dengan representasi HEX dari 0x00- 0xFF. Oleh karena itu hex akan menggandakan panjang output yang diperlukan, itu berarti output 20 byte akan membuat string hex panjang 40 karakter, misalnya:

2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

Perhatikan bahwa tidak perlu menggunakan pengkodean hex. Anda juga bisa menggunakan sesuatu seperti base64 . Hex sering disukai karena lebih mudah dibaca oleh manusia dan memiliki panjang keluaran yang ditentukan tanpa perlu bantalan.

Anda dapat mengonversi array byte ke hex dengan fungsi JDK saja:

new BigInteger(1, token).toString(16)

Namun perlu dicatat bahwa BigIntegerakan menafsirkan array byte yang diberikan sebagai angka dan bukan sebagai string byte. Itu berarti nol di depan tidak akan dikeluarkan dan string yang dihasilkan mungkin lebih pendek dari 40 karakter.

Menggunakan Perpustakaan untuk Menyandikan ke HEX

Anda sekarang dapat menyalin dan menempelkan metode byte-to-hex yang belum diuji dari Stack Overflow atau menggunakan dependensi besar seperti Guava .

Untuk memiliki solusi masuk untuk sebagian besar masalah terkait byte, saya menerapkan utilitas untuk menangani kasus ini: bytes-java (Github)

Untuk mengonversi array byte intisikan pesan Anda, Anda cukup melakukannya

String hex = Bytes.wrap(md.digest(subject)).encodeHex();

atau Anda bisa menggunakan fitur hash bawaan

String hex =  Bytes.from(subject).hashSha1().encodeHex();

2

Base 64 Representasi SHA1Hash:

String hashedVal = Base64.getEncoder().encodeToString(DigestUtils.sha1(stringValue.getBytes(Charset.forName("UTF-8"))));

1

Alasan ini tidak berhasil adalah ketika Anda menelepon String(md.digest(convertme)), Anda memberi tahu Java untuk menafsirkan urutan byte terenkripsi sebagai String. Yang Anda inginkan adalah mengubah byte menjadi karakter heksadesimal.


0

Konversi byte array menjadi hex string.

public static String toSHA1(byte[] convertme) {
    final char[] HEX_CHARS = "0123456789ABCDEF".toCharArray();
    MessageDigest md = null;
    try {
        md = MessageDigest.getInstance("SHA-1");
    }
    catch(NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    byte[] buf = md.digest(convertme);
    char[] chars = new char[2 * buf.length];
    for (int i = 0; i < buf.length; ++i) {
        chars[2 * i] = HEX_CHARS[(buf[i] & 0xF0) >>> 4];
        chars[2 * i + 1] = HEX_CHARS[buf[i] & 0x0F];
    }
    return new String(chars);
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.