SHA1'e Java Dizesi


158

Java SHA1 dönüştürücü basit bir String yapmaya çalışıyorum ve bu ne var ...

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

Geçtiğimde toSHA1("password".getBytes()), [�a�ɹ??�%l�3~��.muhtemelen UTF-8 gibi basit bir kodlama düzeltmesi olduğunu biliyorum, ancak birisi bana istediğimi elde etmek için ne yapmam gerektiğini söyleyebilir 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8mi? Yoksa bunu tamamen yanlış mı yapıyorum?


Algoritma SHA1kısa çizgi içermiyor, bunun bir fark yaratıp yaratmayacağını bilmiyorum.
Scrum Meister

Aradığınızda karakter kodlamasını belirtmek iyi bir uygulamadır getBytes(), örneğin kullanıntoSHA1("password".getBytes("UTF-8"))
Qwerky

Yanıtlar:


183

GÜNCELLEME Bu işi sizin için yapmak
için Apache Commons Codec (sürüm 1.7+) kullanabilirsiniz.

DigestUtils.sha1Hex (stringToConvertToSHexRepresentation)

Bu öneri için @ Jon Onstott'a teşekkürler .


Eski Cevap
Bayt Dizinizi Hex String'e dönüştürün. Real'in Nasıl Yapacağını anlatır .

return byteArrayToHexString(md.digest(convertme))

ve (Real'in Nasıl Yapılır'dan kopyalandı)

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, Base64 kullanarak daha kompakt temsil alabilirsiniz. Apache Commons Codec API 1.4 , tüm acıyı ortadan kaldırmak için bu güzel yardımcı programa sahiptir. buraya bakın


4
base64 ve sha1 çok farklıdır - onları alternatif olarak önermeyin.
Ryan A.

13
@RyanA .: Anladığım kadarıyla, base64'ü SHA1 karma kodlamasını onaltılık kodlamaya alternatif olarak önerir (tamamen SHA1'e alternatif olarak değil).
helmbert

Henüz denemedim, ama bunun nasıl çalıştığını açıklamak ister misiniz?
Jivay

11
Neden DigestUtils.sha1Hex("my string")tekerleği yeniden icat etmek gibi bir kütüphane kullanmıyorsunuz (el ile hex'e nasıl dönüştürüleceğini bilmek ilginç olsa da)?
Jon Onstott

3
Çünkü bu cevap yazıldığında DigestUtils (1.7 Eylül 2012'de yayınlandı) bu özelliğe sahip değildi. Bunu işaret ettiğiniz için teşekkürler. +1
Nishant

67

Bu benim dize sha1 dönüştürmek benim çözümdür. Android uygulamamda iyi çalışıyor:

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
Uyarıdan kaçınmak için bunun java.util.Formatter olduğunu ve sonunda bir formatter.close () gerektiğini belirtmek isteyebilirsiniz.
Eric Chen

Shoudln't encryptPassword("test")ve echo test|sha1sumlinux terminal çıkışı aynı sonucu veriyor mu? Yapmazlar.
Tulains Córdova

@ TulainsCórdova Konsolun çağrılması ile ilgili olarak: Kullanırsanız echo test, satır sonu içeren çıkışa yönlendirilir sha1sum. İzleyen satır sonu olmadan düz bir dize karmasını istiyorsanız, kullanabilirsiniz echo -n test | sha1sum. -nParametre yapan echohat ara atlama.
MrSnrub

Sorudan daha az, ama genel olarak daha fazla: encryptPassword() Kimlik doğrulama verilerini saklamak için kullanılan sesleriniz. Kodlama işleminin tohumlama uygulanmadığı için sözlük saldırılarına açık olduğunu unutmayın. Uygulamanız için bir sorun olup olmadığını güvenlik ortamınızı kontrol edin!
EagleRainbow


32

SHA-1 (ve diğer tüm karma algoritmalar) ikili verileri döndürür. Bu, (Java'da) bir ürettikleri anlamına gelir byte[]. Bu bytedizi yok değil sadece bir çevirmek edemez araçlar herhangi bir spesifik karakterleri temsil Stringsenin yaptığın gibi.

A'ya ihtiyacınız varsa , bunu bir olarak temsil edilebilecek bir şekilde Stringbiçimlendirmeniz byte[]gerekir String(aksi takdirde, byte[]etrafını saklayın ).

byte[]Yazdırılabilir karakterler olarak keyfi temsil etmenin iki yaygın yolu BASE64 veya basit altıgen Dizelerdir (yani her birini temsil eder)byte iki onaltılık basamakla ). Bir hex-String üretmeye çalıştığınız anlaşılıyor.

Başka bir tuzak da var: Eğer SHA-1 bir Java almak istiyorsanız String, o zaman bu dönüştürmek için gereken Stringbir için byte[](SHA-1 giriş bir olduğu gibi ilk byte[]sıra). Gösterdiğiniz myString.getBytes()gibi kullanırsanız, platform varsayılan kodlamasını kullanır ve bu nedenle çalıştırdığınız ortama bağlı olur (örneğin, işletim sisteminizin dil / yerel ayarına göre farklı veriler döndürebilir).

Daha iyi bir çözüm için kullanılmak üzere kodlamayı belirtmektir String-to- byte[]böyle dönüşüm: myString.getBytes("UTF-8"). UTF-8'i (veya her Unicode karakterini temsil edebilecek başka bir kodlamayı) seçmek burada en güvenli seçimdir.


27

Bu, bir dizeyi onaltılık biçime dönüştürürken kullanılabilecek basit bir çözümdür:

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

Uyarı: '0' ile başlayan karmalar için karma oluşturma yanlış. 39 karakterden oluşan bir String alacaksınız.
philn

@philn çözüm önerebilir misiniz?
Nikita Koksharov

1
Sanırım, yeterli baştaki sıfırlarla bir bayttan [] büyük bir tamsayı oluşturursanız, bu 0'lar kaybolur. Böylece, "0" altıgen dizgi gösterimi orada olmayacak ve 39 veya daha az karakterle bir karmaya yol açacaktır. Yukarıda petrnohejls çözümü kullandım ve iyi çalışıyor ...
philn

25

Sadece apache commons codec kütüphanesini kullanın. DigestUtils adında bir yardımcı sınıf var

Detaylara girmeye gerek yok.


51
Kabul
etmiyorum

12
Soru, ayrıntılara girmek için zamanınız olup olmadığıdır. Bütün mesele genellikle bunu zamanında yapmaktır.Herkes bir öğrenci değildir ya da tüm detayları öğrenme lüksüne sahip değildir.
DaTroop

DigestUtils bir bayt dizisi döndürür, böylece Hex.encodeHexString üzerinden çalıştırmanız gereken dize gösterimini elde edebilirsiniz. Java: 2014 ve hala tek adımlı bir sha yöntemimiz yok
ryber

5
Bir adım SHA-1 yöntemi String result = DigestUtils.sha1Hex("An input string"):; o)
Jon Onstott

18

Daha önce belirtildiği gibi apache ortak kodek kullanın. Spring mensupları tarafından da tavsiye edilir (Spring doc'daki DigestUtils'e bakın). Örneğin:

DigestUtils.sha1Hex(b);

Kesinlikle burada en yüksek oy alan cevap kullanmaz.


7

Base64 kodlamasını kullanmanız gerektiğinden düzgün yazdırılmıyor. Java 8 ile Base64 kodlayıcı sınıfını kullanarak kodlayabilirsiniz .

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

Sonuç

Bu size beklenen çıktıyı verecektir 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8


1
@Devenv üç nokta SHA-1, sha1'e dönüşen orijinal kodunu koruyacağı anlamına gelir. OP'nin asıl sorunu, dizeyi doğru yazdırmaktı.
Eduardo Dennis

4

İleti Özeti (karma) bayt [], bayt [] çıkışında

İleti özeti, ham bayt dizisini alan ve ham bayt dizisini (aka byte[]) döndüren bir işlev olarak tanımlanır . Örneğin SHA-1 (Güvenli Karma Algoritma 1) , 160 bit veya 20 baytlık bir sindirim boyutuna sahiptir. Ham bayt dizileri genellikle yorumlanamaz karakter kodlamaları gibi UTF-8 her sırayla değil her bayt kodlama dair bir yasal olduğundan,. Yani onları a Stringile dönüştürmek :

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

bazı yasadışı diziler oluşturabilir veya tanımlanmamış Unicode eşlemeleri için kod işaretçileri olabilir :

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

İkiden Metne Kodlama

Bunun için ikili-metin kodlaması kullanılır. Karma ile en çok kullanılanı HEX kodlaması veya Base16'dır . Temel olarak, bir bayt değeri olabilir 0için 255(veya -128ile 127HEX gösterimine denk imzalı) 0x00- 0xFF. Bu nedenle hex, çıktının gerekli uzunluğunu iki katına çıkaracaktır, yani 20 baytlık bir çıktı 40 karakter uzunluğunda bir hex dizgisi oluşturacaktır, örneğin:

2fd4e1c67a2d28fced849ee1bb76e7391b93eb12

Onaltılık kodlama kullanılmasının gerekli olmadığını unutmayın. Ayrıca base64 gibi bir şey kullanabilirsiniz . Hex genellikle tercih edilir, çünkü insanlar tarafından daha kolay okunabilir ve dolguya ihtiyaç duyulmadan tanımlı bir çıkış uzunluğuna sahiptir.

Bir bayt dizisini yalnızca JDK işlevselliği ile hex'e dönüştürebilirsiniz:

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

Bununla birlikte, BigIntegerverilen bayt dizisini bayt dizesi olarak değil sayı olarak yorumlayacağına dikkat edin . Bu, baştaki sıfırların çıkmayacağı ve sonuçtaki dizenin 40 karakterden kısa olabileceği anlamına gelir.

HEX Kodlaması için Kütüphaneleri Kullanma

Artık Yığın Taşması'ndan denenmemiş bir bayt-onaltılık yöntemini kopyalayıp yapıştırabilir veya Guava gibi büyük bağımlılıklar kullanabilirsiniz .

Baytla ilgili sorunların çoğuna yönelik bir çözüm bulmak için, bu durumları ele alacak bir yardımcı program uyguladım: bytes-java (Github)

Mesaj özet bayt dizinizi dönüştürmek için

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

veya yerleşik karma özelliğini kullanabilirsiniz

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

2

Base 64 SHA1Hash'in Temsili :

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

1

Bunun işe yaramamasının nedeni String(md.digest(convertme)), aradığınızda Java'ya şifrelenmiş bayt dizisini Dize olarak yorumlamasını söylemenizdir. İstediğiniz baytları onaltılık karakterlere dönüştürmektir.


0

Bayt dizisini onaltılı dizeye dönüştür.

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);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.