Memukul string dengan Sha256

141

Saya mencoba untuk hash string menggunakan SHA256, saya menggunakan kode berikut:

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

Namun, kode ini memberikan hasil yang sangat berbeda dibandingkan dengan teman saya php, serta generator online (seperti generator ini )

Adakah yang tahu apa kesalahannya? Basis yang berbeda?

Nattfrosten
sumber
17
Di luar topik, tetapi perlu diingat bahwa membuat StringBuilder dan menggunakan AppendFormat alih-alih String.Format di loop foreach Anda akan mencegah kode Anda dari membuat banyak objek string sia-sia.
Marcel Lamothe

Jawaban:

154

Encoding.Unicodeadalah nama menyesatkan Microsoft untuk UTF-16 (pengodean lebar-ganda, digunakan di dunia Windows untuk alasan historis tetapi tidak digunakan oleh orang lain). http://msdn.microsoft.com/en-us/library/system.text.encoding.unicode.aspx

Jika Anda memeriksa bytesarray Anda, Anda akan melihat bahwa setiap byte kedua adalah 0x00(karena pengodean lebar-ganda).

Anda seharusnya menggunakan Encoding.UTF8.GetBytes.

Tetapi juga, Anda akan melihat hasil yang berbeda tergantung pada apakah Anda menganggap '\0'byte terminating menjadi bagian dari data yang Anda hashing. Hashing dua byte "Hi"akan memberikan hasil yang berbeda dari hashing tiga byte "Hi". Anda harus memutuskan mana yang ingin Anda lakukan. (Mungkin Anda ingin melakukan yang mana saja salah satu kode PHP teman Anda lakukan.)

Untuk teks ASCII, Encoding.UTF8pasti akan cocok. Jika Anda bertujuan untuk kompatibilitas sempurna dengan kode teman Anda, bahkan pada input non-ASCII, Anda sebaiknya mencoba beberapa kasus uji dengan karakter non-ASCII seperti édan dan melihat apakah hasil Anda masih cocok. Jika tidak, Anda harus mencari tahu apa pengkodean yang benar-benar digunakan teman Anda; itu mungkin salah satu dari "halaman kode" 8-bit yang dulu populer sebelum penemuan Unicode. (Sekali lagi, saya pikir Windows adalah alasan utama bahwa siapa pun masih perlu khawatir tentang "halaman kode".)

Quuxplusone
sumber
3
@ Ellmue, Anda mungkin senang mengetahui bahwa "mengurutkan berdasarkan byte yang dikodekan oleh UTF8" dan "mengurutkan berdasarkan titik kode Unicode" adalah sama! (Seperti "menyortir menurut UTF16-disandikan short", tetapi tidak "menyortir oleh UTF16-disandikan byte" kecuali Anda berada di sistem big-endian, yang Windows tidak.) Namun, "menyortir" di Unicode benar-benar sebuah topik rumit yang harus disimpan untuk hari lain.
Quuxplusone
2
@ Elue jangan terlalu percaya diri dengan jawaban yang salah. Cobalah; Anda akan terkejut. Apakah kejutan itu menyenangkan atau tidak, sepenuhnya tergantung pada Anda. :)
Quuxplusone
2
@ Ellmue, “ Bagaimana jika Anda ingin melakukan perbandingan kasus sensitif? ”Anda juga perlu mengonversi byte di UTF-16 jika Anda ingin melakukan hal-hal semacam ini. Fakta bahwa itu panjang tetap tidak membantu sedikit pun.
Arturo Torres Sánchez
2
"Tidak digunakan oleh orang lain" adalah klaim yang cukup menarik, karena Java secara internal menangani string seperti UTF-16 juga ...
Sami Kuhmonen
4
@Elmue "Komentar Anda salah: UTF16 adalah Unicode." Anda salah. "Unicode" adalah standar yang memberikan angka (titik kode) ke mesin terbang. Kecuali pasangan pengganti, itu tidak menyatakan bagaimana mewakili angka-angka itu sebagai byte. UTF16 menentukan titik kode <--> byte. Unicode menentukan glyphs <--> poin kode.
antiduh
103

Saya juga punya masalah dengan gaya implementasi yang lain, tetapi saya lupa di mana saya mendapatkannya sejak 2 tahun yang lalu.

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

Ketika saya memasukkan sesuatu seperti abcdefghi2013karena suatu alasan itu memberikan hasil dan hasil yang berbeda dalam kesalahan dalam modul login saya. Kemudian saya mencoba memodifikasi kode dengan cara yang sama seperti yang disarankan oleh Quuxplusone dan mengubah pengkodean dari ASCIIke UTF8maka akhirnya bekerja!

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

Terima kasih lagi Quuxplusone untuk jawaban yang indah dan terperinci! :)

Nico Dumdum
sumber
solusi Anda berhasil untuk saya. tetapi saya memiliki kasus yang berbeda. itu dengan sha512 dan baris kode yang memecahkan masalah saya adalah hash += bit.ToString("x2");saya punya pertanyaan di sini: Saya menggunakan Convert.ToBase64String(byte[] encryptedBytes)untuk mengkonversi kembali dari byte ke string. itu memberi saya hasil yang berbeda. jadi apa perbedaan antara kedua metode konversi dari byte ke string ..?
Keval Langalia
Apakah mungkin untuk menggunakan beberapa penyesuaian di sini (seperti vektor inisialisasi saya sendiri) atau apakah menambahkan / menambahkan opsi string acak saja?
FrenkyB
Saya tidak begitu yakin apa yang Anda maksud. Ini hanya fungsi hashing yang sangat sederhana dan Anda selalu dapat menambahkan / menyesuaikannya sesuka Anda. Dengan menambahkan / menambahkan string acak, maksud Anda pengasinan? Nah itu salah satu cara yang baik untuk menyesuaikannya untuk keamanan lebih lanjut.
Nico Dumdum
Tidak disarankan hanya menggunakan hashing SHA tanpa faktor kerja untuk menyimpan kata sandi. Dengan kata lain, proses hashing kata sandi harus sangat lambat, untuk mencegah peretas menebak dengan cepat. Gunakan Bcrypt, atau Scrypt untuk keamanan yang lebih baik.
Ton Snoei
@TonSnoei Ya itu benar. Namun, ini adalah beberapa kode lama dari beberapa aplikasi sistem internal kuno di perguruan tinggi yang tidak digunakan lagi dan saya benar-benar tidak akan merekomendasikan ini sendiri. Selain itu, utas ini secara khusus tentang penyandian SHA256 dan tidak secara langsung tentang kata sandi. Meskipun, saya tidak akan keberatan mengeditnya untuk menghapus referensi kata sandi jika itu menggelitik keinginan Anda.
Nico Dumdum
6
public static string ComputeSHA256Hash(string text)
{
    using (var sha256 = new SHA256Managed())
    {
        return BitConverter.ToString(sha256.ComputeHash(Encoding.UTF8.GetBytes(text))).Replace("-", "");
    }                
}

Alasan mengapa Anda mendapatkan hasil yang berbeda adalah karena Anda tidak menggunakan pengkodean string yang sama. Tautan yang Anda masukkan untuk situs web online yang menghitung SHA256 menggunakan Pengkodean UTF8, sedangkan dalam contoh Anda, Anda menggunakan Pengodean Unicode. Mereka adalah dua pengkodean yang berbeda, sehingga Anda tidak mendapatkan hasil yang sama. Dengan contoh di atas Anda mendapatkan hash SHA256 yang sama dari situs web tertaut. Anda perlu menggunakan penyandian yang sama juga di PHP.

Minimum Mutlak Setiap Pengembang Perangkat Lunak, Sepenuhnya Pasti Harus Tahu Tentang Unicode dan Karakter (Tidak Ada Alasan!)

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

Mobil
sumber
4

Dalam versi PHP Anda dapat mengirim 'true' di parameter terakhir, tetapi defaultnya adalah 'false'. Algoritme berikut ini setara dengan fungsi hash PHP default saat meneruskan 'sha256' sebagai parameter pertama:

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;
    }
Rachel
sumber
4
Saya tidak akan menggunakan ASCIIdan melakukan byte[] arrBytes = System.Text.Encoding.UTF8.GetBytes(strData)sebaliknya.
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));
            }
        }
BUSUR
sumber
1
Saya suka fakta bahwa Anda menambahkan garam ^^
Fabian
1

Cara terpendek dan tercepat yang pernah ada. Hanya 1 baris!

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);
Erçin Dedeoğlu
sumber