.NET 中的跨平台加密

.NET 中的加密操作由操作系统 (OS) 库完成。 此依赖项具有以下优势:

  • .NET 应用程序从操作系统可靠性中获益。 对于 OS 供应商而言,确保加密函式库安全应该高度优先考虑。 为此,它们提供了系统管理员应该应用的更新。
  • 如果 OS 库是 FIPS 验证的,则 .NET 应用有权访问经过 FIPS 验证的算法。

对 OS 库的依赖也意味着,.NET 应用只能使用操作系统支持的加密功能。 虽然所有平台都支持某些核心功能,但 .NET 支持的某些功能无法在某些平台上使用。 本文列出了每个平台支持的功能。

本文假设您已熟悉如何在 .NET 中进行加密。 有关详细信息,请参阅 .Net 加密模型.NET 加密服务

哈希算法

除浏览器 WASM 上的 .NET 外,所有哈希算法和基于哈希的消息身份验证 (HMAC) 类(包括 *Managed 类)都遵从操作系统库。 在浏览器 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

已验证加密

分别通过 System.Security.Cryptography.AesCcmSystem.Security.Cryptography.AesGcmSystem.Security.Cryptography.ChaCha20Poly1305 类为 AES-CCM、AES-GCM 和 ChaCha20Poly1305 提供经过身份验证的加密 (AE) 支持。

由于身份验证加密需要较新的平台 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 对第三方代码不支持 AES-GCM 或 ChaCha20Poly1305,直到 macOS 10.15。 在 .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。

RSA on Windows

RSA 本机互操作

.NET 公开类型以允许程序与 .NET 加密代码使用的 OS 库进行互操作。 所涉及的类型不会在平台之间转换,只应在必要时直接使用。

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

1 在非 Windows 上,RSACryptoServiceProvider 可用于与现有程序兼容。 在这种情况下,任何需要 OS 互操作的方法(如打开命名密钥)都会引发 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 CNG Windows 10。 有关详细信息,请参阅 CNG 命名椭圆曲线。 命名曲线在早期版本的 Windows 中不可用,Windows 7 中的三条曲线除外。

3 使用显式曲线参数导出需要 OS 库支持,在 Apple 平台或早期版本的 Windows 上不可用。

4 Android 对某些曲线的支持取决于 Android 版本。 Android 分销商也可以选择在其 Android 版本中添加或删除曲线。

RSA 本机互操作

.NET 公开类型以允许程序与 .NET 加密代码使用的 OS 库进行互操作。 所涉及的类型不会在平台之间转换,只应在必要时直接使用。

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

* 在 macOS 上,如果安装了 OpenSSL,并且可以通过动态库加载找到相应的 libcrypto dylib,则 ECDsaOpenSsl 有效。 如果找不到相应的库,将引发异常。

ECDH

ECDSA(椭圆曲线数字签名算法)密钥生成由 OS 库完成,并受其大小限制和性能特征的限制。

ECDiffieHellman 类支持 ECDH 计算的“原始”值,以及通过以下密钥派生函数提供支持:

  • HASH(Z)
  • HASH (前||Z ||追加)
  • HMAC (键,Z)
  • HMAC (键,前||Z ||追加)
  • HMAC (Z、Z)
  • HASH (Z、前||Z ||追加)
  • Tls11Prf (标签、种子)

.NET 8 中引入了“原始”密钥派生。

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 CNG Windows 10。 有关详细信息,请参阅 CNG 命名椭圆曲线。 命名曲线在早期版本的 Windows 中不可用,Windows 7 中的三条曲线除外。

3 使用显式曲线参数导出需要 OS 库支持,在 Apple 平台或早期版本的 Windows 上不可用。

4 Android 对某些曲线的支持取决于 Android 版本。 Android 分销商也可以选择在其 Android 版本中添加或删除曲线。

ECDH 本机互操作

.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 不符。

DSA on Windows

DSA 本机互操作

.NET 公开类型以允许程序与 .NET 加密代码使用的 OS 库进行互操作。 所涉及的类型不会在平台之间转换,只应在必要时直接使用。

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

1 在非 Windows 上,DSACryptoServiceProvider 可用于与现有程序兼容。 在这种情况下,任何需要系统互操作的方法(如打开命名密钥)都会引发 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 上,存储是在首次写入时创建的,默认情况下不存在用户存储区,因此打开 CurrentUser\MyExistingOnly 可能会失败。

在 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 结果的解释。 在 macOS 上,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 上,当通过其授权信息访问记录在成功的 X509Chain 生成下载中间 CA 时,CurrentUser\Intermediate 存储将用作缓存。 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 上,CurrentUser\Disallowed 和 LocalMachine\Disallowed 存储是对其信任设置为 Always Deny 的证书的相应 SecTrustSettings 结果的解释。

不存在的存储

方案 Windows Linux macOS iOS、tvOS、MacCatalyst Android
打开不存在的存储 (ExistingOnly)
打开 CurrentUser 不存在的存储 (ReadWrite) ⚠️
打开 LocalMachine 不存在的存储 (ReadWrite)

在 macOS 上,只支持在 CurrentUser 位置创建具有 X509STORE API 的自定义存储。 它将创建一个新的密钥链,在用户的密钥链目录中没有密码 (~/Library/Keychains)。 若要创建具有密码的密钥链,可以为 SecKeychainCreate 使用 P/Invoke。 同样,SecKeychainOpen 可用于在不同位置打开密钥链。 根据当前用户的权限,可以将生成的 IntPtr 传递给 new X509Store(IntPtr),以获取支持读写存储。

X509Chain

macOS 不支持脱机 CRL 使用率,因此 X509RevocationMode.Offline 将被视为 X509RevocationMode.Online

macOS 不支持在 CRL(证书吊销列表)/OCSP(联机证书状态协议) /AIA(授权信息访问)下载时出现用户启动的超时,因此 X509ChainPolicy.UrlRetrievalTimeout 会被忽略。

其他资源