.NET 中的跨平台加密

.NET 中的密碼編譯作業是由作業系統 (OS) 程式庫完成。 此相依性具有下列優點:

  • .NET 應用程式受益於 OS 可靠性。 OS 廠商的首要工作是讓密碼編譯程式庫保持安全免於產生弱點。 若要這樣做,其會提供系統管理員應套用的更新。
  • 如果 OS 程式庫經過 FIPS 驗證,則 .NET 應用程式可以存取經 FIPS 驗證的演算法。

OS 程式庫的相依性也表示 .NET 應用程式只能使用 OS 支援的密碼編譯功能。 雖然所有平台都支援某些核心功能,但 .NET 支援的功能無法在某些平台上使用。 本文會識別每個平台上支援的功能。

本文假設您已熟悉 .NET 中的密碼編譯。 如需詳細資訊,請參閱 .NET 密碼編譯模型.NET 密碼編譯服務

雜湊演算法

所有雜湊演算法和雜湊型訊息驗證 (HMAC) 類別,包括 *Managed 類別,都會延遲至 OS 程式庫,但瀏覽器 WASM 上的 .NET 除外。 在瀏覽器 WASM 中,SHA-1、SHA-2-256、SHA-2-384、SHA-2-512 是使用受控程式碼實作。

SHA-3

.NET 8 引進了 SHA-3 雜湊演算法的支援,包括 SHAKE-128 和 SHAKE-256。 Windows 11 組建 25324 或更新版本以及具有 OpenSSL 1.1.1 或更新版本的 Linux 上目前支援 SHA-3。

對稱加密

基礎加密和鏈結是由系統程式庫完成。

加密 + 模式 Windows Linux macOS iOS、tvOS、MacCatalyst Android
AES-CBC ✔️ ✔️ ✔️ ✔️ ✔️
AES-ECB ✔️ ✔️ ✔️ ✔️ ✔️
AES-CFB8 ✔️ ✔️ ✔️ ✔️ ✔️
AES-CFB128 ✔️ ✔️ ✔️ ✔️ ✔️
3DES-CBC ✔️ ✔️ ✔️ ✔️ ✔️
3DES-ECB ✔️ ✔️ ✔️ ✔️ ✔️
3DES-CFB8 ✔️ ✔️ ✔️ ✔️ ✔️
3DES-CFB64 ✔️ ✔️ ✔️ ✔️ ✔️
DES-CBC ✔️ ✔️ ✔️ ✔️ ✔️
DES-ECB ✔️ ✔️ ✔️ ✔️ ✔️
DES-CFB8 ✔️ ✔️ ✔️ ✔️ ✔️
RC2-CBC ✔️ ✔️ ✔️ ✔️
RC2-ECB ✔️ ✔️ ✔️ ✔️
RC2-CFB

已驗證的加密

已驗證的加密 (AE) 支援分別透過 System.Security.Cryptography.AesCcmSystem.Security.Cryptography.AesGcmSystem.Security.Cryptography.ChaCha20Poly1305 類別提供 AES-CCM、AES-GCM 和 ChaCha20Poly1305。

由於驗證加密需要較新的平台 API 來支援演算法,因此可能並非所有平台上都支援。 演算法類別上的 IsSupported 靜態屬性可用來在執行階段偵測目前平台是否支援演算法。

加密 + 模式 Windows Linux macOS iOS、tvOS、MacCatalyst Android 瀏覽器
AES-GCM ✔️ ✔️ ⚠️ ✔️
AES-CCM ✔️ ✔️ ⚠️ ✔️
ChaCha20Poly1305 Windows 10 組建 20142+ OpenSSL 1.1.0+ ⚠️ API 層級 28+

macOS 上的 AES-CCM

在 macOS 上,系統程式庫不支援對第三方程式碼使用 AES-CCM,因此 AesCcm 類別會使用 OpenSSL 來獲得支援。 macOS 上的使用者必須取得適當的 OpenSSL (libcrypto) 複本,才能讓此類型運作,且其必須位於系統預設會從中載入程式庫的路徑中。 建議您從套件管理員 (例如 Homebrew) 安裝 OpenSSL。

macOS 中包含的 libcrypto.0.9.7.dyliblibcrypto.0.9.8.dylib 程式庫是來自舊版的 OpenSSL,因此並不會用到。 libcrypto.35.dyliblibcrypto.41.dyliblibcrypto.42.dylib 程式庫是來自 LibreSSL,因此並不會用到。

macOS 上的 AES-GCM 和 ChaCha20Poly1305

在 macOS 10.15 之前,macOS 不支援對第三方程式碼使用 AES-GCM 或 ChaCha20Poly1305。 在 .NET 8 之前,AesGcmChaCha20Poly1305 具有與 AES-CCM 相同的需求,且使用者必須安裝 OpenSSL,這些類型才能運作。

從 .NET 8 開始,macOS 上的 .NET 會針對 AES-GCM 和 ChaCha20Poly1305 使用 Apple 的 CryptoKit 架構。 使用者不需要在 macOS 上為 AES-GCM 或 ChaCha20Poly1305 安裝或設定任何其他相依性。

AES-CCM 金鑰、nonce 和標籤

  • 金鑰大小

    AES-CCM 適用於 128、192 和 256 位元金鑰。

  • Nonce 大小

    AesCcm 類別支援 56、64、72、80、88、96 和 104 位元 (7、8、9、10、11、12 和 13 位元組) nonce。

  • 標籤大小

    AesCcm 類別支援建立或處理 32、48、64、80、96、112 和 128 位元 (4、8、10、12、14 和 16 位元組) 標籤。

AES-GCM 金鑰、nonce 和標籤

  • 金鑰大小

    AES-GCM 適用於 128、192 和 256 位元金鑰。

  • Nonce 大小

    AesGcm 類別僅支援 96 位元 (12 位元組) nonce。

  • 標籤大小:在 Windows 和 Linux 上,AesGcm 類別支援建立或處理 96、104、112、120 和 128 位元 (12、13、14、15 和 16 位元組) 標籤。 在 macOS 上,由於 CryptoKit 架構的限制,標籤大小限制為 128 位元 (16 位元組)。

ChaCha20Poly1305 金鑰、nonce 和標籤。

ChaCha20Poly1305 針對金鑰、nonce 和驗證標籤具有固定大小。 ChaCha20Poly1305 一律會使用 256 位元金鑰、96 位元 (12 位元組) nonce 和 128 位元 (16 位元組) 標籤。

非對稱密碼編譯

本節包含下列子區段:

RSA

RSA (Rivest–Shamir–Adleman) 金鑰產生是由 OS 程式庫執行,並受限於其大小限制和效能特色。

RSA 金鑰作業是由 OS 程式庫所執行,而可載入的金鑰類型則受限於 OS 需求。

.NET 不會公開「原始」(未填補) RSA 作業。

填補和摘要支援會因平台而異:

填補模式 Windows (CNG) Linux (OpenSSL) macOS iOS、tvOS、MacCatalyst Android Windows (CAPI)
PKCS1 加密 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
OAEP - SHA-1 ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
OAEP - SHA-2 ✔️ ✔️ ✔️ ✔️ ✔️
OAEP - SHA-32 Windows 11 組建 25324+ OpenSSL 1.1.1+
PKCS1 簽章 (MD5、SHA-1) ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
PKCS1 簽章 (SHA-2) ✔️ ✔️ ✔️ ✔️ ✔️ ⚠️1
PKCS1 簽章 (SHA-3)2 Windows 11 組建 25324+ OpenSSL 1.1.1+
PSS ✔️ ✔️ ✔️ ✔️ ✔️

1 Windows CryptoAPI (CAPI) 能夠搭配 SHA-2 演算法使用 PKCS1 簽章。 但是,個別 RSA 物件可能會載入不支援的密碼編譯服務提供者 (CSP)。

2 需要 .NET 8。

Windows 上的 RSA

RSA 原生 interop

.NET 會公開類型,以允許程式與 .NET 密碼編譯程式碼所使用的 OS 程式庫交互操作。 涉及的類型不會在平台之間轉譯,且應該僅在必要時直接使用。

類型 Windows Linux macOS iOS、tvOS、MacCatalyst Android
RSACryptoServiceProvider ✔️ ⚠️1 ⚠️1 ⚠️1 ⚠️1
RSACng ✔️
RSAOpenSsl ✔️ ⚠️2

1 在 Windows 上,RSACryptoServiceProvider 可與現有程式搭配使用以獲得相容性。 在此情況下,任何需要 OS Interop 的方法 (例如開啟具名金鑰) 都會擲回 PlatformNotSupportedException

2 在 macOS 上,如果已安裝 OpenSSL,且可以透過動態程式庫載入找到適當的 libcrypto dylib,則 RSAOpenSsl 運作正常。 如果找不到適當的程式庫,將會擲回例外狀況。

ECDSA

ECDSA (橢圓曲線數位簽章演算法) 金鑰產生是由 OS 程式庫完成,且受限於其大小限制和效能特色。

ECDSA 金鑰曲線是由 OS 程式庫所定義,並受限於其限制。

橢圓曲線 Windows 10 Windows 7 - 8.1 Linux macOS iOS、tvOS、MacCatalyst Android
NIST P-256 (secp256r1) ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
NIST P-384 (secp384r1) ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
NIST P-521 (secp521r1) ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Brainpool 曲線 (為具名曲線) ✔️ ⚠️1 ⚠️4
其他具名曲線 ⚠️2 ⚠️1 ⚠️4
明確曲線 ✔️ ✔️ ✔️
匯出或匯入為明確 ✔️ 3 ✔️ 3 3 ✔️

1 Linux 發行版本並未全都支援相同的具名曲線。

2 在 Windows 10 中,已將具名曲線的支援新增至 Windows CNG。 如需詳細資訊,請參閱 CNG 具名橢圓曲線。 除了 Windows 7 中三條曲線外,舊版 Windows 中無法使用具名曲線。

3 使用明確曲線參數匯出需要 OS 程式庫支援,但無法在 Apple 平台或舊版 Windows 上使用。

4 某些曲線的 Android 支援取決於 Android 版本。 Android 散發者也可以選擇從其 Android 組建新增或移除曲線。

ECDSA 原生 Interop

.NET 會公開類型,以允許程式與 .NET 密碼編譯程式碼所使用的 OS 程式庫交互操作。 涉及的類型不會在平台之間轉譯,且應該僅在必要時直接使用。

類型 Windows Linux macOS iOS、tvOS、MacCatalyst Android
ECDsaCng ✔️
ECDsaOpenSsl ✔️ ⚠️*

* 在 macOS 上,如果系統中已安裝 OpenSSL,且可以透過動態程式庫載入找到適當的 libcrypto dylib,則 ECDsaOpenSsl 運作正常。 如果找不到適當的程式庫,將會擲回例外狀況。

ECDH

ECDH (橢圓曲線 Diffie-Hellman) 金鑰產生是由 OS 程式庫完成,並受限於其大小限制和效能特色。

ECDiffieHellman 類別支援 ECDH 計算的「原始」值,以及透過下列金鑰衍生函數:

  • HASH(Z)
  • HASH(prepend || Z || append)
  • HMAC(key, Z)
  • HMAC(key, prepend || Z || append)
  • HMAC(Z, Z)
  • HMAC(Z, prepend || Z || append)
  • Tls11Prf(label, seed)

「原始」金鑰衍生是在 .NET 8 中引進。

ECDH 金鑰曲線是由 OS 程式庫所定義,並受限於其限制。

橢圓曲線 Windows 10 Windows 7 - 8.1 Linux macOS iOS、tvOS、MacCatalyst Android
NIST P-256 (secp256r1) ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
NIST P-384 (secp384r1) ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
NIST P-521 (secp521r1) ✔️ ✔️ ✔️ ✔️ ✔️ ✔️
Brainpool 曲線 (為具名曲線) ✔️ ⚠️1 ⚠️4
其他具名曲線 ⚠️2 ⚠️1 ⚠️4
明確曲線 ✔️ ✔️ ✔️
匯出或匯入為明確 ✔️ 3 ✔️ 3 3 ✔️

1 Linux 發行版本並未全都支援相同的具名曲線。

2 在 Windows 10 中,已將具名曲線的支援新增至 Windows CNG。 如需詳細資訊,請參閱 CNG 具名橢圓曲線。 除了 Windows 7 中三條曲線外,舊版 Windows 中無法使用具名曲線。

3 使用明確曲線參數匯出需要 OS 程式庫支援,但無法在 Apple 平台或舊版 Windows 上使用。

4 某些曲線的 Android 支援取決於 Android 版本。 Android 散發者也可以選擇從其 Android 組建新增或移除曲線。

ECDH 原生 interop

.NET 會公開類型,以允許程式與 .NET 所使用的 OS 程式庫交互操作。 涉及的類型不會在平台之間轉譯,且應該僅在必要時直接使用。

類型 Windows Linux macOS iOS、tvOS、MacCatalyst Android
ECDiffieHellmanCng ✔️
ECDiffieHellmanOpenSsl ✔️ ⚠️*

* 在 macOS 上,如果已安裝 OpenSSL,且可以透過動態程式庫載入找到適當的 libcrypto dylib,則 ECDiffieHellmanOpenSsl 運作正常。 如果找不到適當的程式庫,將會擲回例外狀況。

DSA

DSA (數位簽章演算法) 金鑰產生是由系統程式庫執行,且受限於其大小限制和效能特色。

函式 Windows CNG Linux macOS Windows CAPI iOS、tvOS、MacCatalyst Android
金鑰建立 (<= 1024 位元) ✔️ ✔️ ✔️ ✔️
金鑰建立 (> 1024 位元) ✔️ ✔️ ✔️
載入金鑰 (<= 1024 位元) ✔️ ✔️ ✔️ ✔️ ✔️
載入金鑰 (> 1024 位元) ✔️ ✔️ ⚠️* ✔️
FIPS 186-2 ✔️ ✔️ ✔️ ✔️ ✔️
FIPS 186-3 (SHA-2 簽章) ✔️ ✔️ ✔️

* macOS 會載入大於 1024 位元的 DSA 金鑰,但這些金鑰的行為並未定義。 這些金鑰不會根據 FIPS 186-3 運作。

Windows 上的 DSA

DSA 原生 interop

.NET 會公開類型,以允許程式與 .NET 密碼編譯程式碼所使用的 OS 程式庫交互操作。 涉及的類型不會在平台之間轉譯,且應該僅在必要時直接使用。

類型 Windows Linux macOS iOS、tvOS、MacCatalyst Android
DSACryptoServiceProvider ✔️ ⚠️1 ⚠️1 ⚠️1
DSACng ✔️
DSAOpenSsl ✔️ ⚠️2

1 在 Windows 上,DSACryptoServiceProvider 可與現有程式搭配使用以獲得相容性。 在此情況下,任何需要系統 Interop 的方法 (例如開啟具名金鑰) 都會擲回 PlatformNotSupportedException

2 在 macOS 上,如果已安裝 OpenSSL,且可以透過動態程式庫載入找到適當的 libcrypto dylib,則 DSAOpenSsl 運作正常。 如果找不到適當的程式庫,將會擲回例外狀況。

X.509 憑證

.NET 中大部分 X.509 憑證的支援都來自 OS 程式庫。 若要將憑證載入 .NET 中的 X509Certificate2X509Certificate 執行個體,憑證必須由基礎 OS 程式庫載入。

讀取 PKCS12/PFX

案例 Windows Linux macOS iOS、tvOS、MacCatalyst Android
空的 ✔️ ✔️ ✔️ ✔️ ✔️
一個憑證,沒有私密金鑰 ✔️ ✔️ ✔️ ✔️ ✔️
一個憑證,含有私密金鑰 ✔️ ✔️ ✔️ ✔️ ✔️
多個憑證,沒有私密金鑰 ✔️ ✔️ ✔️ ✔️ ✔️
多個憑證,一個私密金鑰 ✔️ ✔️ ✔️ ✔️ ✔️
多個憑證,多個私密金鑰 ✔️ ✔️ ✔️ ✔️ ✔️

撰寫 PKCS12/PFX

案例 Windows Linux macOS iOS、tvOS、MacCatalyst Android
空的 ✔️ ✔️ ✔️ ✔️ ✔️
一個憑證,沒有私密金鑰 ✔️ ✔️ ✔️ ✔️ ✔️
一個憑證,含有私密金鑰 ✔️ ✔️ ✔️ ✔️ ✔️
多個憑證,沒有私密金鑰 ✔️ ✔️ ✔️ ✔️ ✔️
多個憑證,一個私密金鑰 ✔️ ✔️ ✔️ ✔️ ✔️
多個憑證,多個私密金鑰 ✔️ ✔️ ✔️ ✔️ ✔️
暫時載入 ✔️ ✔️ ✔️ ✔️

macOS 無法在沒有金鑰鏈物件的情況下載入憑證私密金鑰,這需要寫入磁碟。 會針對 PFX 載入自動建立金鑰鏈,且不再使用時會予以刪除。 因為 X509KeyStorageFlags.EphemeralKeySet 選項表示私密金鑰不應該寫入磁碟,所以判斷 macOS 上的旗標會導致 PlatformNotSupportedException

撰寫 PKCS7 憑證集合

Windows 和 Linux 都會發出 DER 編碼的 PKCS7 Blob。 macOS 會發出無限長度 CER 編碼的 PKCS7 Blob。

X509Store

在 Windows 上,X509Store 類別是 Windows 憑證存放區 API 的標記法。 這些 API 在 .NET Core 和 .NET 5 中的運作方式與 .NET Framework 相同。

在 Windows 上,X509Store 類別是系統信任決策的投影 (唯讀)、使用者信任決策 (讀寫),以及使用者金鑰儲存體 (讀寫)。

下表顯示每個平台中支援哪些案例。 對於不支援的案例 (資料表中的 ❌),會擲回 CryptographicException

我的存放區

案例 Windows Linux macOS iOS、tvOS、MacCatalyst Android
開啟 CurrentUser\My (ReadOnly) ✔️ ✔️ ✔️ ✔️ ✔️
開啟 CurrentUser\My (ReadWrite) ✔️ ✔️ ✔️ ✔️ ✔️
開啟 CurrentUser\My (ExistingOnly) ✔️ ⚠️ ✔️ ✔️ ✔️
開啟 LocalMachine\My ✔️ ✔️ ✔️ ✔️

在 Linux 上,會在第一次寫入時建立存放區,且預設沒有任何使用者存放區存在,因此使用 ExistingOnly 開啟 CurrentUser\My 時可能會失敗。

在 macOS 上,CurrentUser\My 存放區是使用者的預設金鑰鏈,預設為 login.keychainLocalMachine\My 存放區是 System.keychain

根存放區

案例 Windows Linux macOS iOS、tvOS、MacCatalyst Android
開啟 CurrentUser\Root (ReadOnly) ✔️ ✔️ ✔️ ✔️
開啟 CurrentUser\Root (ReadWrite) ✔️ ✔️
開啟 CurrentUser\Root (ExistingOnly) ✔️ ⚠️ ✔️ (如果 ReadOnly) ✔️ (如果 ReadOnly)
開啟 LocalMachine\Root (ReadOnly) ✔️ ✔️ ✔️ ✔️
開啟 LocalMachine\Root (ReadWrite) ✔️
開啟 LocalMachine\Root (ExistingOnly) ✔️ ⚠️ ✔️ (如果 ReadOnly) ✔️ (如果 ReadOnly)

在 Linux 上,LocalMachine\Root 存放區是 OpenSSL 預設路徑中 CA 套件組合的解譯。

在 macOS 上,CurrentUser\Root 存放區是使用者信任網域 SecTrustSettings 結果的解譯。 LocalMachine\Root 存放區是管理員和系統信任網域 SecTrustSettings 結果的解譯。

中繼存放區

案例 Windows Linux macOS iOS、tvOS、MacCatalyst Android
開啟 CurrentUser\Intermediate (ReadOnly) ✔️ ✔️ ✔️
開啟 CurrentUser\Intermediate (ReadWrite) ✔️ ✔️
開啟 CurrentUser\Intermediate (ExistingOnly) ✔️ ⚠️ ✔️ (如果 ReadOnly)
開啟 LocalMachine\Intermediate (ReadOnly) ✔️ ✔️ ✔️
開啟 LocalMachine\Intermediate (ReadWrite) ✔️
開啟 LocalMachine\Intermediate (ExistingOnly) ✔️ ⚠️ ✔️ (如果 ReadOnly)

在 Linux 上,CurrentUser\Intermediate 存放區會在成功 X509Chain 組建的授權單位資訊存取記錄下載中繼 CA 時做為快取。 LocalMachine\Intermediate 存放區是 OpenSSL 預設路徑中 CA 套件組合的解譯。

在 macOS 上,CurrentUser\Intermediate 存放區會被視為自訂存放區。 新增至此存放區的憑證不會影響 X.509 鏈結建置。

不允許的存放區

案例 Windows Linux macOS iOS、tvOS、MacCatalyst Android
開啟 CurrentUser\Disallowed (ReadOnly) ✔️ ⚠️ ✔️ ✔️ ✔️
開啟 CurrentUser\Disallowed (ReadWrite) ✔️ ⚠️
開啟 CurrentUser\Disallowed (ExistingOnly) ✔️ ⚠️ ✔️ (如果 ReadOnly) ✔️ (如果 ReadOnly) ✔️ (如果 ReadOnly)
開啟 LocalMachine\Disallowed (ReadOnly) ✔️ ✔️ ✔️ ✔️
開啟 LocalMachine\Disallowed (ReadWrite) ✔️
開啟 LocalMachine\Disallowed (ExistingOnly) ✔️ ✔️ (如果 ReadOnly) ✔️ (如果 ReadOnly) ✔️ (如果 ReadOnly)

在 Linux 上,不會在鏈結建置中使用 Disallowed 存放區,且嘗試將內容新增至其中會導致 CryptographicException。 如果已取得內容,則會在開啟 Disallowed 存放區時擲回 CryptographicException

在 macOS 上,針對信任設定為 Always Deny 的憑證,CurrentUser\Disallowed 和 LocalMachine\Disallowed 存放區是適當 SecTrustSettings 結果的解譯。

不存在的存放區

案例 Windows Linux macOS iOS、tvOS、MacCatalyst Android
開啟不存在的存放區 (ExistingOnly)
開啟 CurrentUser 不存在的存放區 (ReadWrite) ✔️ ✔️ ⚠️
開啟 LocalMachine 不存在的存放區 (ReadWrite) ✔️

在 macOS 上,只有 CurrentUser 位置才支援使用 X509Store API 建立自訂存放區。 其會在使用者的金鑰鏈目錄中建立沒有密碼的新金鑰鏈 (~/Library/Keychains)。 若要使用密碼建立金鑰鏈,可以使用 P/Invoke SecKeychainCreate。 同樣地,SecKeychainOpen 可用來在不同的位置開啟金鑰鏈。 結果 IntPtr 可以傳遞至 new X509Store(IntPtr),以取得可讀取/寫入的存放區,受限於目前使用者的權限。

X509Chain

macOS 不支援離線 CRL 使用率,因此會將 X509RevocationMode.Offline 視為 X509RevocationMode.Online

macOS 不支援 CRL (憑證撤銷清單) /OCSP (線上憑證狀態通訊協定) / AIA (授權單位資訊存取) 下載的使用者起始逾時,因此會忽略 X509ChainPolicy.UrlRetrievalTimeout

其他資源