Java'da SHA-256 aracılığıyla Hash String


111

Buraya ve genel olarak internete bakarak Bouncy Castle'ı buldum . Java'da bir String'in SHA-256 Hash'ini oluşturmak için Bouncy Castle'ı (veya ücretsiz olarak kullanılabilen başka bir yardımcı programı) kullanmak istiyorum. Onların belgelerine baktığımda, yapmak istediklerime dair iyi örnekler bulamıyorum. Burada kimse bana yardım edebilir mi?

Yanıtlar:


264

Bir dizeye hashing uygulamak için yerleşik MessageDigest sınıfını kullanın:

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.nio.charset.StandardCharsets;
import java.math.BigInteger;

public class CryptoHash {
  public static void main(String[] args) throws NoSuchAlgorithmException {
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    String text = "Text to hash, cryptographically.";

    // Change this to UTF-16 if needed
    md.update(text.getBytes(StandardCharsets.UTF_8));
    byte[] digest = md.digest();

    String hex = String.format("%064x", new BigInteger(1, digest));
    System.out.println(hex);
  }
}

Yukarıdaki digestkod parçacığında , hash uygulanmış dizeyi hexiçerir ve sol sıfır dolgulu onaltılık bir ASCII dizesi içerir.


2
@Harry Pham, hash her zaman aynı olmalıdır, ancak daha fazla bilgi olmadan neden farklı olanları aldığınızı söylemek zor olacaktır. Muhtemelen yeni bir soru açmalısın.
Brendan Long

2
@Harry Pham: Aradıktan sonra digestdahili durum sıfırlanır; böylece daha önce güncelleme yapmadan tekrar çağırdığınızda, boş dizenin karmasını alırsınız.
Debilski

3
@BrendanLong Şimdi, String'e nasıl geri digestdönülür?
Sajad

1
@Sajjad En sevdiğiniz base64 kodlama işlevini kullanın. Ben kişisel olarak Apache Commons'ta olanı beğendim .
Brendan Long

1
@Adam Hayır, bu yanıltıcı. Bir bayt dizisi üzerinde "toString" çağrısı yapmak, bayt dizisinin içeriğini String'e dönüştürmekten farklı bir sonuç üretiyor, Brendan Longs cevabı daha uygun
max.mustermann

30

Bu, çalışma zamanı kitaplıklarında zaten uygulanmıştır.

public static String calc(InputStream is) {
    String output;
    int read;
    byte[] buffer = new byte[8192];

    try {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        while ((read = is.read(buffer)) > 0) {
            digest.update(buffer, 0, read);
        }
        byte[] hash = digest.digest();
        BigInteger bigInt = new BigInteger(1, hash);
        output = bigInt.toString(16);
        while ( output.length() < 32 ) {
            output = "0"+output;
        }
    } 
    catch (Exception e) {
        e.printStackTrace(System.err);
        return null;
    }

    return output;
}

Bir JEE6 + ortamında JAXB DataTypeConverter da kullanılabilir :

import javax.xml.bind.DatatypeConverter;

String hash = DatatypeConverter.printHexBinary( 
           MessageDigest.getInstance("MD5").digest("SOMESTRING".getBytes("UTF-8")));

3
bu sürümde bir hata var (en azından bugün itibariyle ve java8 @ win7 ile). '1234'ü hash etmeyi deneyin. sonuç '03ac67 ...' ile başlamalı ama aslında '3ac67 ...' ile başlıyor
Chris

@Chris teşekkürler, bunu burada düzelttim, ancak şu anda bu konuda en sevdiğim daha iyi bir çözüm buldum: stackoverflow.com/questions/415953/…
istifleyici

1
Bu eski iş parçacığının yeni okuyucuları için: @stacker tarafından atıfta bulunulan favori (MD5-hash) artık güvenli değildir ( en.wikipedia.org/wiki/MD5 ).
mortensi

1
Koşul output.length () <64 olmalıdır, 32 değil.
Sampo

Aynı tuz kullanılarak oluşturulan iki farklı karma değeri nasıl karşılaştırabiliriz? Birinin giriş formundan geldiğini varsayalım (karşılaştırmadan önce Salt kullanarak hashing işlemi yapmanız gerekir) ve diğeri db'den gelir ve sonra bu ikisini nasıl karşılaştırabiliriz?
Pra_A

16

BouncyCastle kitaplığına ihtiyacınız yok. Aşağıdaki kod, Integer.toHexString işlevi kullanılarak nasıl yapılacağını gösterir

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

Bu gönderiden user1452273'e özel teşekkürler: Java'da sha256 ile bazı dizeler nasıl hash edilir?

İyi çalışmaya devam edin!


9

Karma kodları herhangi bir jce sağlayıcısıyla kullanırken, önce algoritmanın bir örneğini almaya çalışırsınız, ardından onu karma hale getirilmesini istediğiniz verilerle güncellersiniz ve bitirdiğinizde karma değerini almak için özet çağırırsınız.

MessageDigest sha = MessageDigest.getInstance("SHA-256");
sha.update(in.getBytes());
byte[] digest = sha.digest();

İhtiyaçlarınıza göre bir base64 veya hex kodlanmış sürüm almak için özeti kullanabilirsiniz


Merak ettiğim için digest(), atlayarak doğrudan girdi bayt dizisine gidebilir misiniz update()?
ladenedge

Fark ettiğim bir şey, bunun "SHA-256" ile çalıştığı, "SHA256" nın bir NoSuchAlgorithmException oluşturduğu. Önemli değil.
knpwrs

9
Brandon benim yorumum gereğince, yok kullanmak String.getBytes()bir kodlama belirtmeden. Şu anda bu kod, farklı platformlarda farklı sonuçlar verebilir - bu, iyi tanımlanmış bir hash için bozuk davranıştır.
Jon Skeet

@ladenedge evet - dizeniz kısaysa @KPthunder sağınız @Jon Skeet dizenin içeriğine bağlıdır - ancak evet, kaydetme tarafında olması için getBytes kodlama dizesi ekleyin
Nikolaus Gradwohl

7

Java 8: Base64 mevcut:

    MessageDigest md = MessageDigest.getInstance( "SHA-512" );
    md.update( inbytes );
    byte[] aMessageDigest = md.digest();

    String outEncoded = Base64.getEncoder().encodeToString( aMessageDigest );
    return( outEncoded );

5

Sanırım SHA-256'sız nispeten eski bir Java Sürümü kullanıyorsunuz. Bu nedenle BouncyCastle Sağlayıcısını, java sürümünüzde önceden sağlanan 'Güvenlik Sağlayıcılarına' eklemelisiniz.

    // NEEDED if you are using a Java version without SHA-256    
    Security.addProvider(new BouncyCastleProvider());

    // then go as usual 
    MessageDigest md = MessageDigest.getInstance("SHA-256");
    String text = "my string...";
    md.update(text.getBytes("UTF-8")); // or UTF-16 if needed
    byte[] digest = md.digest();

JDK'da bulunan nispeten önemsiz seçime kıyasla epeyce yeni MessageDigest ekleyen BouncyCastle'dan bahsetmek için +1.
mjuarez

0
return new String(Hex.encode(digest));

4
Paket / sağlayıcı bilgisi olmadan "Hex" sınıfı pek yardımcı olmaz. Ve eğer bu Apache Commons Codec'ten Hex ise, return Hex.encodeHexString(digest)onun yerine kullanırdım.
40'ta eckes

0

Java 8'i kullanma

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

-1

Bu, paketin ardından "org.bouncycastle.util.encoders.Hex" ile çalışacaktır.

return new String(Hex.encode(digest));

Bouncycastle kavanozda.

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.