.NET 用同一套 API 封装各平台的密码学实现——Windows 上是 CNG,Linux 上是 OpenSSL,macOS 上是 Apple 的库:ECDsa、RSA、MLDsa、MLKem 等。本次检查在 Ubuntu 24.04 上运行 .NET 10.0.13,其底层的 OpenSSL 为 3.0.13,这个版本影响了多项结果。
默认的签名编码与大多数服务端库正好相反。ECDsa.SignData 返回 64 字节的 IEEE P1363 r‖s,VerifyData 也按这种格式解析;要使用 DER,两个调用都需要传入 DSASignatureFormat.Rfc3279DerSequence。因此 .NET 开箱即与 JWS 和 WebCrypto 一致,而与 OpenSSL、Java 的 SHA256withECDSA 和 Go 的 SignASN1 不一致。任何格式错误或不匹配的签名都会让 VerifyData 返回 false,所以用默认格式检查 DER 签名时,结果与伪造签名毫无二致——示例展示了这两种结果,DER ⇄ 原始格式转换器则能看出你手里的是哪一种。
在 Linux 上,ECDSA 支持 P-256 到 P-521、secp256k1 和 Brainpool r1 曲线,全部通过 OpenSSL 实现。SignHash 对你自行计算的摘要签名,nonce 是随机的,s 不做规范化,验证时接受 high-S。基类库中没有 Ed25519 或 Ed448 类;EdDSA 需要借助面向 .NET 的 Bouncy Castle 或其他包。
MLKem、MLDsa、SlhDsa 和 CompositeMLDsa 在 .NET 10 中都存在,但各自的 IsSupported 取决于平台。在 OpenSSL 3.0.13 上,它们全部为 false;OpenSSL 在 3.5 中才加入 ML-KEM 和 ML-DSA,因此在 Linux 上需要提供该版本 OpenSSL 的发行版,在 Windows 上则需要相应的 CNG 支持。代码必须检查 IsSupported,不能想当然;本页尚未在任何结果为 true 的平台上做过验证。
密钥可以从 SPKI 和 PKCS#8(PEM 或 DER,加密与否均可)、SEC1 EC PRIVATE KEY 以及 ECParameters 中的原始坐标导入;不支持导入 SEC1 点或 JWK。可以用 PFX 查看器查看 PFX 文件包。