Sha256 ile bir dizeyi karma yapmak


141

SHA256 kullanarak bir dize karma çalışın, aşağıdaki kodu kullanıyorum:

using System;
using System.Security.Cryptography;
using System.Text;
 public class Hash
    {
    public static string getHashSha256(string text)
    {
        byte[] bytes = Encoding.Unicode.GetBytes(text);
        SHA256Managed hashstring = new SHA256Managed();
        byte[] hash = hashstring.ComputeHash(bytes);
        string hashString = string.Empty;
        foreach (byte x in hash)
        {
            hashString += String.Format("{0:x2}", x);
        }
        return hashString;
    }
}

Ancak, bu kod arkadaşlarım php yanı sıra çevrimiçi jeneratörler ( Bu jeneratör gibi ) ile karşılaştırıldığında önemli ölçüde farklı sonuçlar verir

Hatanın ne olduğunu bilen var mı? Farklı üsler?


17
Konu dışı, ancak bir StringBuilder oluşturma ve foreach döngü içinde String.Format yerine AppendFormat kullanmanın kodunuzun gereksiz bir şekilde çok sayıda dize nesnesi oluşturmasını engelleyeceğini unutmayın.
Marcel Lamothe

Yanıtlar:


155

Encoding.UnicodeMicrosoft'un UTF-16 için yanıltıcı adıdır (Windows dünyasında tarihsel nedenlerle kullanılan ancak başkaları tarafından kullanılmayan çift genişlikli kodlama). http://msdn.microsoft.com/en-us/library/system.text.encoding.unicode.aspx

Dizinizi bytesincelerseniz, her iki baytın olduğunu görürsünüz 0x00(çift geniş kodlama nedeniyle).

Bunun Encoding.UTF8.GetBytesyerine kullanıyor olmalısınız .

Ancak, sonlanan '\0'baytın, karma yaptığınız verilerin bir parçası olduğunu düşünüp düşünmediğinize bağlı olarak farklı sonuçlar göreceksiniz . İki baytın "Hi"karması, üç baytın hash edilmesinden farklı bir sonuç verecektir "Hi". Hangisini yapmak istediğinize karar vermelisiniz. (Muhtemelen arkadaşınızın PHP kodunun hangisini yapıyorsa yapmak istersiniz.)

ASCII metni için Encoding.UTF8kesinlikle uygun olacaktır. Eğer hedefliyor iseniz mükemmel bile ASCII olmayan girdiler üzerinde, arkadaşınızın kodu ile uyumluluk, daha iyi gibi ASCII olmayan karakterler ile birkaç test durumları çalışacaktı éve ve sonuçları hala maç olmadığını görmek. Değilse, arkadaşınızın hangi kodlamayı gerçekten kullandığını bulmanız gerekir; Unicode'un icadından önce popüler olan 8 bitlik "kod sayfalarından" biri olabilir. (Yine, Windows'un herkesin "kod sayfaları" konusunda endişelenmesinin ana nedeni olduğunu düşünüyorum.)


3
@Elmue, "UTF8 kodlu baytlara göre sıralama" ve "Unicode kod noktalarına göre sıralama" işlevlerinin eşdeğer olduğunu öğrenmekten memnun olabilirsiniz! (As "UTF16 kodlanmış göre sıralama olduğunu shorts", ancak değil Windows olmayan bir big-endian sistemi üzerinde olmadıkça "UTF16 kodlanmış bayt göre sıralama".) Ancak, Unicode "sıralama" dır gerçekten başka bir gün için saklanması gereken karmaşık bir konu.
Quuxplusone

2
@Elmue yanlış cevaplarınıza bu kadar güvenmiyor. Denemek; şaşıracaksın. Sürprizin hoş veya tatsız olması tamamen size kalmış. :)
Quuxplusone

2
@Elmue, “ Ya büyük / küçük harf duyarsız bir karşılaştırma yapmak isterseniz? “Bu tür şeyler yapmak istiyorsanız, UTF-16'daki baytları da dönüştürmeniz gerekir. Sabit uzunlukta olması bir bite yardımcı olmaz.
Arturo Torres Sánchez

2
"Başkaları tarafından kullanılmayan" oldukça ilginç bir iddia, çünkü Java dahili olarak UTF-16 olarak dizeleri
işliyor

4
@Elmue "Yorumlarınız yanlış: UTF16 Unicode." Hatalısınız. "Unicode" gliflere sayı (kod noktaları) atayan bir standarttır. Yedek çiftler hariç, bu sayıların bayt olarak nasıl temsil edileceğini belirtmez. UTF16, kod noktalarını <--> bayt olarak belirtir. Unicode, glif <--> kod noktalarını belirtir.
antiduh

103

Başka bir uygulama tarzı ile de bu sorunu yaşadım ama 2 yıl önce olduğu için nereden aldığımı unuttum.

static string sha256(string randomString)
{
    var crypt = new SHA256Managed();
    string hash = String.Empty;
    byte[] crypto = crypt.ComputeHash(Encoding.ASCII.GetBytes(randomString));
    foreach (byte theByte in crypto)
    {
        hash += theByte.ToString("x2");
    }
    return hash;
}

Herhangi bir abcdefghi2013nedenden dolayı bir şey girdiğimde, giriş sonuçlarımda farklı sonuçlar ve hatalarla sonuçlanır. Quuxplusone önerdiği ve gelen kodlama değiştikçe Sonra kodu aynı şekilde değiştirerek denedik ASCIIiçin UTF8o zaman son olarak çalıştı!

static string sha256(string randomString)
{
    var crypt = new System.Security.Cryptography.SHA256Managed();
    var hash = new System.Text.StringBuilder();
    byte[] crypto = crypt.ComputeHash(Encoding.UTF8.GetBytes(randomString));
    foreach (byte theByte in crypto)
    {
        hash.Append(theByte.ToString("x2"));
    }
    return hash.ToString();
}

Harika ve ayrıntılı cevap için tekrar Quuxplusone teşekkürler! :)


çözümünüz benim için çalıştı. ama farklı bir durumum var. sha512 ve sorunumu çözen kod satırı ile hash += bit.ToString("x2");burada bir sorum var: Bayttan Convert.ToBase64String(byte[] encryptedBytes)dizeye geri dönüştürmek için kullanıyordum . bu bana farklı bir sonuç verdi. yani bayttan dizeye dönüştürme bu iki yöntem arasındaki fark nedir?
Keval Langalia

Burada (kendi başlatma vektörüm gibi) bazı özelleştirme kullanmak mümkün mü yoksa yalnızca rastgele dize ekleme / ekleme seçeneği var mı?
FrenkyB

Ne demek istediğinden emin değilim. Bu sadece çok basit bir hashing fonksiyonu ve istediğiniz zaman ekleyebilirsiniz / özelleştirebilirsiniz. Rastgele dize ekleyerek / ekleyerek tuzlama mı demek istediniz? Bu, daha fazla güvenlik için özelleştirmenin iyi bir yoludur.
Nico Dumdum

Şifreleri saklamak için bir çalışma faktörü olmadan sadece SHA karma işleminin kullanılması önerilmez. Başka bir deyişle, bilgisayar korsanlarının hızlı tahmin etmesini önlemek için parolanın karma işleminin önemli ölçüde yavaş olması gerekir. Daha iyi güvenlik için Bcrypt veya Scrypt kullanın.
Ton Snoei

@TonSnoei Evet, bu doğru. Ancak, bu kolejde artık kimsenin kullanmadığı bazı eski iç sistem uygulamasından eski bir kod ve bunu gerçekten kendim tavsiye etmem. Ayrıca, bu iş parçacığı doğrudan şifreler hakkında değil, SHA256 kodlaması ile ilgilidir. Rağmen, fantezi gıdıklıyorsa şifreleri referansları kaldırmak için onu düzenleme sakıncası olmaz.
Nico Dumdum

6
public static string ComputeSHA256Hash(string text)
{
    using (var sha256 = new SHA256Managed())
    {
        return BitConverter.ToString(sha256.ComputeHash(Encoding.UTF8.GetBytes(text))).Replace("-", "");
    }                
}

Farklı sonuçlar almanızın nedeni, aynı dize kodlamasını kullanmamanızdır. SHA256'yı hesaplayan çevrimiçi web sitesi için koyduğunuz bağlantı UTF8 Kodlaması'nı kullanırken örneğinizde Unicode Kodlaması'nı kullandınız. Bunlar iki farklı kodlamadır, böylece aynı sonucu elde edemezsiniz. Yukarıdaki örnekle bağlantılı web sitesinin aynı SHA256 karmasını elde edersiniz. Aynı kodlamayı PHP'de de kullanmanız gerekir.

Mutlak Minimum Her Yazılım Geliştiricisi Kesinlikle, Olumlu Unicode ve Karakter Kümeleri Hakkında Bilmeli (Bahane Yok!)

https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/


4

PHP sürümünde son parametrede 'true' gönderebilirsiniz, ancak varsayılan 'false' değeridir. Aşağıdaki algoritma, ilk parametre olarak 'sha256' iletilirken varsayılan PHP'nin karma işlevine eşdeğerdir:

public static string GetSha256FromString(string strData)
    {
        var message = Encoding.ASCII.GetBytes(strData);
        SHA256Managed hashString = new SHA256Managed();
        string hex = "";

        var hashValue = hashString.ComputeHash(message);
        foreach (byte x in hashValue)
        {
            hex += String.Format("{0:x2}", x);
        }
        return hex;
    }

4
Ben kullanmam ASCIIve byte[] arrBytes = System.Text.Encoding.UTF8.GetBytes(strData)onun yerine yapmam .
c00000fd

3
public string EncryptPassword(string password, string saltorusername)
        {
            using (var sha256 = SHA256.Create())
            {
                var saltedPassword = string.Format("{0}{1}", salt, password);
                byte[] saltedPasswordAsBytes = Encoding.UTF8.GetBytes(saltedPassword);
                return Convert.ToBase64String(sha256.ComputeHash(saltedPasswordAsBytes));
            }
        }

1
biraz tuz eklediğiniz gerçeğini seviyorum ^^
Fabian

1

Şimdiye kadarki en kısa ve en hızlı yol. Sadece 1 satır!

public static string StringSha256Hash(string text) =>
    string.IsNullOrEmpty(text) ? string.Empty : BitConverter.ToString(new System.Security.Cryptography.SHA256Managed().ComputeHash(System.Text.Encoding.UTF8.GetBytes(text))).Replace("-", string.Empty);

-2

Bu çalışma benim için .NET Core 3.1.
Ancak .NET 5 önizleme 7'de değil.

using System;
using System.Security.Cryptography;
using System.Text;

namespace PortalAplicaciones.Shared.Models
{
    public class Encriptar
    {
        public static string EncriptaPassWord(string Password)
        {
            try
            {
                SHA256Managed hasher = new SHA256Managed();

                byte[] pwdBytes = new UTF8Encoding().GetBytes(Password);
                byte[] keyBytes = hasher.ComputeHash(pwdBytes);

                hasher.Dispose();
                return Convert.ToBase64String(keyBytes);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message, ex);
            }
        }  
    }
}
 

1
StackOverflow'a hoş geldiniz. Lütfen önerdiğiniz çözümün neden OP'nin sorununu çözebileceğini düşündüğünüzü açıklayın.
Peter Csala

1
Lütfen tekrar atma istisnasından kaçının. Bununla orijinal StackTrace'i kaybedersiniz.
Peter Csala
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.