共用方式為


.NET 中的加密、數位簽名和哈希演算法概觀

本文提供 .NET 支援的加密方法和做法概觀,包括 ClickOnce 指令清單。

密碼編譯簡介

因特網之類的公用網路不提供實體之間安全通訊的方法。 透過這類網路的通訊很容易被未經授權的第三方讀取或修改。 密碼編譯可協助保護數據不受檢視、提供偵測資料是否已修改的方法,以及協助提供透過其他不安全通道的安全通訊方式。 例如,數據可以使用密碼編譯演算法進行加密、以加密狀態傳輸,稍後再由預期合作物件解密。 如果第三方攔截加密的數據,則很難解密。

在 .NET 中,命名空間中的 System.Security.Cryptography 類別會為您管理許多密碼編譯的詳細數據。 有些是作業系統實作的包裝函式,有些則純粹是受管理的實作。 您不需要是密碼編譯專家才能使用這些類別。 當您建立其中一個加密演算法類別的新實例時,會自動產生密鑰以方便使用,且預設屬性盡可能安全。

密碼技術原始元件

在使用密碼編譯的一般情況下,兩方(Alice 和 Bob)會透過不安全的通道進行通訊。 Alice 和 Bob 想要確保他們的通訊讓任何可能正在聆聽的人都無法理解。 此外,由於 Alice 和 Bob 位於遠端位置,Alice 必須確定她在傳輸期間從未由任何人修改從 Bob 接收的資訊。 此外,她必須確定資訊確實來自 Bob,而不是來自模擬 Bob 的人。

密碼編譯可用來達成下列目標:

  • 機密性:協助保護使用者的身分識別或數據免於讀取。

  • 數據完整性:協助保護數據免於變更。

  • 驗證:確保資料來自特定方。

  • 不可否認:防止特定對象否認他們曾經發送訊息。

若要達成這些目標,您可以使用稱為加密基元的演算法和做法組合來建立加密方案。 下表列出密碼編譯基本類型及其用法。

密碼編譯基本類型 使用
秘密金鑰加密 (對稱密碼編譯) 對資料執行轉換,使其無法由第三方讀取。 這種類型的加密會使用單一共用的秘密密鑰來加密和解密數據。
公鑰加密 (非對稱密碼編譯) 對資料執行轉換,使其無法由第三方讀取。 這種類型的加密會使用公開/私鑰組來加密和解密數據。
密碼編譯簽署 藉由建立該當事方唯一的數位簽章來協助驗證數據源自特定當事方。 此程式也會使用哈希函式。
密碼編譯哈希 將數據從任何長度對應至固定長度位元組序列。 哈希在統計上是唯一的;不同的雙位元組序列不會哈希至相同的值。

Secret-Key 加密

秘密金鑰加密演算法會使用單一秘密金鑰來加密和解密數據。 您必須保護金鑰不被未經授權的人員存取,因為擁有金鑰的任何第三方都可以用它來解密您的資料或加密自己的資料,並聲稱其源自您。

秘密金鑰加密也稱為對稱加密,因為相同的金鑰用於加密和解密。 秘密密鑰加密演算法非常快速(與公鑰演演算法相比),非常適合在大型數據流上執行密碼編譯轉換。 RSA 之類的非對稱加密演算法在可加密的數據量中,數學上會受到限制。 對稱式加密演算法通常不會有這些問題。

稱為區塊加密的秘密金鑰演算法類型一次用來加密一個數據區塊。 區塊加密,例如數據加密標準 (DES)、TripleDES 和進階加密標準 (AES) 會以密碼編譯方式將 n 個字節的輸入區塊轉換成加密位元組的輸出區塊。 如果您想要加密或解密位元組序列,則必須依區塊執行此動作。 因為 n 很小(DES 和 TripleDES 的 8 個字節;16 個字節 [預設值]、24 個字節或 AES 的 32 個字節),因此大於 n 的數據值必須一次加密一個區塊。 小於 n 的數據值必須展開為 n 才能進行處理。

一種簡單的區塊加密形式稱為電子代碼簿(ECB)模式。 ECB 模式不被視為安全,因為它不會使用初始化向量來初始化第一個純文本區塊。 對於指定的秘密金鑰 k,不使用初始化向量的簡單區塊加密會將純文字的相同輸入區塊加密為加密文字的相同輸出區塊。 因此,如果您的輸入純文本數據流中有重複區塊,則輸出加密文字數據流中會有重複區塊。 這些重複的輸出區塊會警示未經授權的使用者所使用的演算法的弱加密,以及可能的攻擊模式。 因此,電子密碼本加密模式非常容易被分析,最終可能導致密鑰被發現。

基類連結庫中提供的區塊加密類別會使用稱為加密區塊鏈結的預設鏈結模式(CBC),不過您可以視需要變更此預設值。

CBC 加密會使用初始化向量 (IV) 來加密第一個純文字區塊,以克服與 ECB 加密相關的問題。 每個後續的純文字區塊都會在加密之前,使用先前的加密文本區塊進行位獨佔 OR (XOR) 作業。 因此,每個加密文本區塊都相依於所有先前的區塊。 使用此系統時,未經授權的使用者可能已知的常見訊息標頭無法用來反向工程密鑰。

入侵使用 CBC 加密加密數據的方法之一,就是對每個可能密鑰執行詳盡的搜尋。 視用來執行加密的金鑰大小而定,這種搜尋會非常耗時,甚至使用最快的計算機,因此是不可行的。 較大的金鑰大小較難以譯碼。 雖然加密在理論上無法讓敵人擷取加密的數據,但它確實會增加這樣做的成本。 如果執行詳盡的搜尋需要三個月的時間,才能擷取只有幾天有意義的數據,則詳盡的搜尋方法是不切實際的。

秘密密鑰加密的缺點是,它假設雙方已就密鑰和 IV 達成一致,並傳達其值。 IV 不會被視為秘密,可以隨著訊息以明文形式傳輸。 不過,金鑰必須保密給未經授權的使用者。 由於這些問題,秘密密鑰加密通常會與公鑰加密搭配使用,以私下傳達密鑰和 IV 的值。

假設Alice和Bob是想要透過不安全通道進行通訊的兩方,他們可能會使用秘密密鑰加密,如下所示:Alice 和Bob同意搭配特定密鑰和IV使用一種特定演算法(例如 AES)。 Alice 撰寫訊息,並建立要傳送訊息的網路串流(可能是命名管道或網路電子郵件)。 接下來,她會使用密鑰和 IV 來加密文字,並透過內部網路將加密的訊息和 IV 傳送給 Bob。 Bob 接收到加密的文字後,使用 IV 和事先同意的密鑰將其解密。 如果攔截傳輸,攔截器就無法復原原始訊息,因為它們不知道密鑰。 在此案例中,只有金鑰必須保持秘密。 在真實世界的案例中,Alice 或 Bob 會產生秘密密鑰,並使用公鑰(非對稱式)加密將秘密(對稱)金鑰傳輸給另一方。 如需公鑰加密的詳細資訊,請參閱下一節。

.NET 提供下列類別來實作秘密金鑰加密演演算法:

  • Aes

  • HMACSHA256HMACSHA384HMACSHA512。 (這些在技術上是秘密密鑰演演算法,因為它們代表使用密碼編譯哈希函式結合秘密密鑰所計算的訊息驗證碼。請參閱本文稍後的 哈希值

Public-Key 加密

公鑰加密使用的私鑰必須保密並不讓未經授權的使用者知道,而公鑰則可以公開給任何人。 公鑰和私鑰會以數學方式連結;使用公鑰加密的數據只能使用私鑰解密,而使用私鑰簽署的數據只能使用公鑰進行驗證。 公鑰可供任何人使用:它用於加密數據以傳送至私鑰的保留者。 公鑰密碼編譯演算法也稱為非對稱演算法,因為需要一個密鑰才能加密數據,而需要另一個密鑰才能解密數據。 基本密碼編譯規則會禁止重複使用密鑰,而且每個通訊會話的兩個密鑰都應該是唯一的。 不過,在實務上,非對稱密鑰通常是長期存在。

兩方 (Alice 和 Bob) 可能會使用公鑰加密,如下所示:首先,Alice 會產生公開/私鑰組。 如果 Bob 想傳送愛麗絲一封加密的訊息,他會要求她提供她的公鑰。 Alice 透過不安全的網路傳送 Bob 她的公鑰,而 Bob 會使用此金鑰來加密訊息。 Bob 會將加密的訊息傳送給 Alice,並使用她的私鑰將它解密。 如果 Bob 透過不安全的通道收到 Alice 的金鑰,例如公用網路,Bob 會開放給中間人攻擊。 因此,Bob 必須向 Alice 確認他有正確的公鑰複本。

在Alice 公鑰傳輸期間,未經授權的代理程式可能會攔截金鑰。 此外,相同的代理程式可能會攔截 Bob 的加密訊息。 不過,代理程式無法使用公鑰解密訊息。 訊息只能使用未傳輸的 Alice 私鑰進行解密。 Alice 不會使用她的私鑰將回復訊息加密給 Bob,因為具有公鑰的任何人都可以解密訊息。 如果Alice想要將訊息傳回Bob,她會要求Bob提供他的公鑰,並使用該公鑰加密她的訊息。 Bob 接著會使用他相關聯的私鑰解密訊息。

在此案例中,Alice 和 Bob 會使用公鑰(非對稱)加密來傳輸秘密(對稱)金鑰,並在其餘會話中使用秘密密鑰加密。

下列清單提供公鑰與秘密金鑰密碼編譯演算法之間的比較:

  • 公鑰密碼編譯演算法會使用固定的緩衝區大小,而秘密密鑰密碼編譯演算法則使用可變長度緩衝區。

  • 公鑰演算法無法如同秘密密鑰演算法般將數據串聯成流,因為它們只能加密少量的數據。 因此,非對稱作業不會使用與對稱作業相同的串流模型。

  • 公鑰加密具有比秘密金鑰加密更大的金鑰空間(金鑰的可能值範圍)。 因此,公鑰加密較不容易遭受嘗試每個可能密鑰的詳盡攻擊。

  • 公鑰很容易散發,因為它們不需要受到保護,前提是有某種方式可以驗證發件者的身分識別。

  • 某些公鑰演演算法(例如 RSA 和 DSA,但不能 Diffie-Hellman),可用來建立數位簽名來驗證數據傳送者的身分識別。

  • 相較於秘密金鑰演演算法,公鑰演演算法的速度非常慢,而且不是設計來加密大量數據。 公鑰演演算法僅適用於傳輸非常少量的數據。 一般而言,公鑰加密用來加密一個金鑰和一個 IV,供秘密密鑰演算法使用。 傳輸金鑰和 IV 之後,秘密金鑰加密會用於會話的其餘部分。

.NET 提供下列類別來實作公鑰演演算法:

RSA 允許加密和簽署,但 DSA 只能用於簽署。 DSA 不如 RSA 那麼安全,我們建議使用 RSA。 Diffie-Hellman 只能用於產生金鑰。 一般而言,公鑰演演算法的使用比私鑰演演算法更有限。

數位簽章

公鑰演演算法也可以用來形成數字簽名。 數位簽名會驗證寄件者的身分識別(如果您信任寄件者的公鑰),並協助保護數據的完整性。 使用Alice所產生的公鑰,Alice 數據的收件者可以藉由比較數位簽名與Alice的數據和Alice的公鑰,來驗證Alice傳送的公鑰。

為了使用公鑰密碼編譯來數位簽署訊息,Alice 會先將哈希演算法套用至訊息,以建立訊息摘要。 訊息摘要是精簡且唯一的數據表示法。 Alice 接著會使用她的私鑰加密訊息摘要,以建立她的個人簽章。 收到訊息和簽章時,Bob 會使用 Alice 的公鑰解密簽章,以復原訊息摘要,並使用 Alice 所使用的相同哈希演算法哈希訊息。 如果 Bob 所計算的訊息摘要完全符合 Alice 收到的訊息摘要,Bob 會確保訊息來自私鑰的擁有者,而且數據尚未修改。 如果 Bob 相信 Alice 是私鑰的擁有者,他就會知道訊息來自 Alice。

備註

任何人都可以驗證簽章,因為發件人的公鑰是常見的知識,而且通常會包含在數位簽名格式中。 此方法不會保留訊息的秘密;若要讓訊息成為秘密,也必須加密它。

.NET 提供下列類別來實作數位簽名演算法:

哈希值

哈希演算法會將任意長度的二進位值對應至固定長度較小的二進位值,稱為哈希值。 哈希值是數據片段的數值表示法。 如果您哈希純文本段落並變更段落的一個字母,則後續的哈希會產生不同的值。 如果哈希的加密強度高,其值將會大幅變更。 例如,如果訊息中一個位元有所變動,強式哈希函數可能會產生相差50%的輸出。 許多輸入值可能會哈希至相同的輸出值。 不過,在計算上是無法找到兩個不同的輸入產生相同的哈希值。

兩方 (Alice 和 Bob) 可以使用哈希函式來確保訊息完整性。 他們會選取哈希演算法來簽署其訊息。 Alice 會撰寫訊息,然後使用選取的演算法建立該訊息的哈希。 然後,他們會遵循下列其中一種方法:

  • Alice 會將純文本訊息和哈希訊息 (數位簽名) 傳送給 Bob。 Bob 會接收和哈希訊息,並將他的哈希值與他從 Alice 收到的哈希值進行比較。 如果哈希值相同,則不會改變訊息。 如果值不相同,那麼訊息在Alice撰寫之後被改變了。

    不幸的是,此方法不會建立寄件人的真實性。 任何人都可以模擬 Alice,並將訊息傳送給 Bob。 他們可以使用相同的哈希演算法來簽署其訊息,而 Bob 可以判斷訊息符合其簽章。 這是一種名為「中間人攻擊」的攻擊形式。 如需詳細資訊,請參閱 新一代密碼編譯 (CNG) 安全通訊範例

  • Alice 透過不安全的公用通道將純文本訊息傳送給 Bob。 她透過安全的私人頻道將哈希訊息傳送給Bob。 Bob 接收純文本訊息後,進行哈希運算,並將結果與私下交換的哈希值進行比較。 如果哈希相符,Bob 知道兩件事:

    • 訊息未改變。

    • 訊息的發件者(Alice)是經過驗證的。

    若要讓這個系統運作,Alice 必須隱藏她的原始哈希值,只讓 Bob 知道。

  • Alice 透過不安全的公用通道將純文本訊息傳送給 Bob,並將哈希訊息放在可公開檢視的網站上。

    此方法可防止任何人修改哈希值,以防止訊息竄改。 雖然訊息及其哈希可由任何人讀取,但哈希值只能由Alice變更。 想要模擬 Alice 的攻擊者需要存取 Alice 的網站。

上述方法都不會防止有人讀取Alice的訊息,因為它們會以純文本傳輸。 完整安全性通常需要數位簽名(訊息簽署)和加密。

.NET 提供下列類別來實作哈希演算法:

.NET 也提供 MD5SHA1。 但已發現 MD5 和 SHA-1 演算法不安全,現在建議改用 SHA-2。 SHA-2 包含 SHA256、SHA384 和 SHA512。

隨機數字產生

隨機數產生是許多密碼編譯作業不可或缺的一部分。 例如,密碼編譯密鑰必須儘可能隨機,以便無法重現它們。 密碼學隨機數產生器必須生成輸出內容,使其在計算上無法預測,且預測的成功機率不能超過一半。 因此,任何預測下一個輸出位的方法都不能比隨機猜測效能更好。 .NET 中的類別會使用隨機數產生器來產生密碼編譯密鑰。

類別 RandomNumberGenerator 是隨機數產生器演算法的實作。

ClickOnce 指令清單

下列密碼編譯類別可讓您取得及驗證使用 ClickOnce 技術部署之應用程式的指令清單簽章相關信息:

此外,下列類別提供特定的簽章資訊:

新一代密碼編譯 (CNG) 類別

新一代密碼編譯 (CNG) 類別提供對原生 CNG 函式的管理包裝器。 (CNG 是 CryptoAPI 的替代者。這些類別具有 「Cng」 作為其名稱的一部分。 CNG 包裝函式類別的核心是 CngKey 索引鍵容器類別,它會抽象化 CNG 密鑰的儲存和使用。 這個類別可讓您安全地儲存金鑰組或公鑰,並使用簡單的字串名稱加以參考。 橢圓曲線型 ECDsaCng 簽章類別和 ECDiffieHellmanCng 加密類別可以使用 CngKey 物件。

類別 CngKey 用於各種不同的額外作業,包括開啟、建立、刪除和匯出密鑰。 它也可讓您存取直接呼叫原生函式時要使用的基礎密鑰句柄。

.NET 也包含各種支援的 CNG 類別,例如:

另請參閱