在 C# 中,從字串產生 SHA-256 雜湊值的方式,是將該字串編碼為 UTF-8 位元組,再把這些位元組傳遞給 System.Security.Cryptography 中的標準 SHA256 演算法,該演算法會回傳一個 32 位元組的摘要,你可以將其格式化為 64 個小寫十六進位字元,或 44 個標準 Base64 字元。C# 的寫法很短——呼叫 SHA256.Create()、再用 Encoding.UTF8.GetBytes 取得的位元組陣列呼叫 ComputeHash,最後把位元組轉成可列印的形式——但每一個步驟都對實際被雜湊的位元組極為敏感。主控台輸出時附加的換行字元、Unicode 正規化方式的差異,或從 UTF-8 切換到 UTF-16,都會改變位元組,進而改變摘要;因此「錯誤」的結果幾乎都是位元組不一致的問題,而不是密碼學本身有 bug。這個類別實作了 NIST FIPS 180-4 和 RFC 6234 中所規範的相同演算法,所以任何符合標準的 SHA-256 工具,對於相同的位元組都會產出相同的摘要;你可以用瀏覽器版的 SHA256 雜湊產生器 對同一段 UTF-8 文字重新計算摘要,藉此驗證你的 C# 結果。

C# 開發者使用 SHA-256 通常基於兩個常見理由:為快取或去重目的對字串建立指紋,或將下載檔案本機計算出的摘要與發佈者公佈的摘要進行比對,以驗證檔案的完整性。兩者都仰賴該演算法在每個平台上的行為一致,而這正是符合 FIPS 180-4 所保證的。接下來的章節會逐步說明程式碼、輸出格式、交叉驗證流程,以及那些會悄悄改變摘要的陷阱。

c# generate sha256 hash from string
在 C# 中從字串產生 SHA256 雜湊並進行驗證

C# 如何從字串計算 SHA-256 雜湊

.NET 執行階段在 System.Security.Cryptography.SHA256 中內建一個符合 FIPS 180-4 的 SHA-256 實作。這個類別繼承自 HashAlgorithm,並覆寫 ComputeHash 來執行標準所定義的 SHA-2 padding、512 位元區塊分割、64 字排程擴充,以及八輪 32 位元工作變數更新。當你呼叫 ComputeHash(byte[]) 時,執行階段會依序雜湊陣列中的每一個位元組,包括任何前置的零、尾端的歸位字元(carriage return),以及某些編碼器加在開頭的位元組順序標記(byte order mark)。結果永遠是 32 個位元組,不會因為輸入長度而改變,這正是為何可列印的十六進位形式永遠是 64 個字元。

C# 的寫法在雜湊之前會把 .NET 字串視為一串 UTF-8 字碼單元(code unit),因為這個演算法是處理位元組,而不是字元。Encoding.UTF8.GetBytes(string) 是標準的橋樑;Encoding.Unicode(UTF-16 LE)會產生不同的位元組序列,因此對任何非 ASCII 字串都會產生不同的摘要。對於純 ASCII 文字,這兩種編碼在 ASCII 子集上恰好相同,但碰到帶重音的字母、表情符號或 CJK 字元時就會分歧,雜湊值也會跟著改變。若你希望摘要能夠被其他語言或平台重現,一定要雜湊該字串的 UTF-8 表示。

C# SHA-256 程式碼:將 UTF-8 字串雜湊為十六進位或 Base64

最精簡的程式碼路徑如下。請將它放在能存取 System.Security.Cryptography、System.Text 與 System 的方法內:

using System.Security.Cryptography;

using System.Text;

using System;

byte[] inputBytes = Encoding.UTF8.GetBytes("hello world");

byte[] digestBytes = SHA256.Create().ComputeHash(inputBytes);

string hex = BitConverter.ToString(digestBytes).Replace("-", string.Empty).ToLowerInvariant();

string base64 = Convert.ToBase64String(digestBytes);

對於字面值 hello world(沒有尾端換行),hex 會變成 b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9,你可以用同一個 Convert.ToBase64String 呼叫把它轉成標準帶 padding 的 Base64。兩種字串描述的是同一組 32 個位元組;兩者互轉不會遺失任何資訊,而十六進位大小寫的選擇只是呈現方式不同而已。

如果你偏好一個會回傳十六進位字串、方便用於記錄或顯示的單行輔助方法,可以把上述模式包成一個 static 方法:

public static string Sha256Hex(string input) {

using var sha = SHA256.Create();

byte[] bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(input));

return BitConverter.ToString(bytes).Replace("-", string.Empty).ToLowerInvariant();

}

using 宣告可確保 SHA256 實例會被釋放,且方法回傳時任何內部緩衝區都會被回收。Convert.ToBase64String(digestBytes) 會給你 API 欄位與 JWT 元件所使用的標準帶 padding Base64 表示;而把連字號去掉後的 BitConverter.ToString 則會給你十六進位。兩種格式描述的是同一個 32 位元組的摘要。

用瀏覽器工具交叉驗證你的 C# 結果

一旦你從 C# 拿到 64 字元的十六進位摘要,最快的確認方式是:在完全相同的位元組上,用一個參考實作再算一次。SHA256 雜湊產生器在瀏覽器中執行標準的 SHA-256 演算法,可接受 UTF-8 文字或檔案位元組,並同時顯示十六進位與 Base64 形式,讓你能直接比對任何一種表示。

交叉驗證包含五個具體步驟:

  1. 在新分頁中開啟 SHA256 雜湊產生器。
  2. 切換到文字模式,並貼上你 C# 程式碼雜湊過的同一段字串。若使用檔案模式,則選擇你本機雜湊過的同一個檔案。
  3. 產生摘要,並複製工具所顯示的 64 字元十六進位值。
  4. 把整段十六進位字串與 C# 的輸出逐字元比對。全部 64 個位置都相符,就代表演算法與輸入位元組是一致的。
  5. 若你的參考值是 Base64,請將工具切換到該檢視,改為比對 44 字元的輸出。

由於這個工具與 System.Security.Cryptography 使用相同的 FIPS 180-4 運算,任何不一致都屬於位元組層級的問題——編碼、隱藏的換行、正規化方式,或選錯了演算法——而不是密碼學實作上的差異。

為什麼 C# 的 SHA-256 摘要可能與參考值不符

大多數「錯誤」的 C# SHA-256 輸出,問題都出在位元組而非演算法本身。下列五個原因幾乎涵蓋了實務上所有的不一致情況:

  • 編碼切換。Encoding.Unicode 會給出 UTF-16 LE 位元組;ASCII 子集與 UTF-8 一致,但任何超出 ASCII 的字元(例如 é、中、🚀)都會改變位元組數與摘要。
  • 隱藏的換行。在 Windows 上 Console.WriteLine 會附加 \r\n,許多編輯器也會在檔案結尾加上一個換行字元,而你的程式碼可能不小心把它一起納入輸入。
  • 十六進位字母大小寫。參考的校驗和偶爾會以大寫十六進位發佈。由於位元組完全相同,摘要其實是相符的;只有字母大小寫不同。
  • Unicode 正規化。同一段可見字串可能存在多種合法的 UTF-8 表示(例如預組態與分解態形式)。若在正規化之前就雜湊,會得到不同的摘要。
  • 選錯演算法。原始的 SHA-256、HMAC-SHA-256,以及「對加鹽字串做 SHA-256」,對同一組字元會產生不同的摘要。請確認兩端都使用原始的 SHA-256。

在偵錯不一致時,最乾淨的做法是從兩端分別計算空字串的摘要並進行比對;空輸入的摘要在 C# 與瀏覽器工具中都以 e3b0c442 這八個字元開頭,這能在你開始偵錯真實輸入之前,先證明演算法與位元組順序是對齊的。

SHA-256 輸出格式比較

同一組 32 個位元組可以有多種列印方式。下方列出 C# 程式碼最常遇到的兩種格式。

格式長度字元集常見用途
小寫十六進位64 個字元0–9, a–f已發佈的校驗和、git commit 雜湊值、廠商下載頁面
標準帶 padding 的 Base6444 個字元A–Z, a–z, 0–9, +, /, =API 承載資料、JWT 元件、精簡的二進位欄位
原始位元組32 個位元組任何 0–255 的位元組值受信任呼叫端之間的內部 API、以二進位格式儲存

十六進位與 Base64 只是呈現方式的選擇;它們編碼的是同一組 32 個位元組,也對應同一個摘要。改變十六進位的字母大小寫只會影響顯示,絕不會改變底層的位元組。當系統要求某一種格式時,請從對應的檢視複製貼上——整合介面上大多數的不一致,其實只是選錯了格式,而不是實作有問題。

SHA-256 在 C# 中無法解決的問題

SHA-256 是單向的摘要演算法,而不是加密,因此沒有金鑰,也沒有支援的反向運算。它同樣無法驗證輸入是由誰產生的:任何人都能對同一組位元組進行雜湊,並得到相同的摘要。若需要基於共享密鑰的認證,請使用 HMAC-SHA-256,它會把一把秘密金鑰與同一個 SHA-256 基本運算結合;若需基於公開金鑰的來源驗證,則必須使用 RSA-PSS 或 ECDSA 等數位簽章機制。

請不要直接以 SHA-256 儲存使用者密碼。這個演算法刻意設計得很快,這讓暴力窮舉變得便宜。帳號系統應使用每個使用者唯一的鹽,並搭配像 PBKDF2、bcrypt、scrypt 或 Argon2 等記憶體密集型(memory-hard)函式,並依目前硬體效能調整參數。SHA-256 仍然是完整性檢查、建立指紋與校驗和驗證的正確工具——這些情境的目標是偵測已知輸入是否遭到意外或惡意的修改。

對於空輸入,標準仍然會產生一個有效的摘要——空位元組字串會雜湊成以 e3b0c442 開頭的著名值——所以工具與 C# 都能直接處理空字串而不需要特例。空格、歸位字元、編輯器附加在結尾的換行,以及 Unicode 正規化形式的選擇,全部都是位元組,任何一個都可能改變最終的摘要。

若想更深入了解,請參閱正確產生 SHA-512 雜湊:完整的 512 位元

若想更深入了解,請參閱線上 UTF-8 轉換器:編碼、解碼與驗證位元組