C# RSA加密解密方法 C#如何使用RSA进行非对称加密

来源:这里教程网 时间:2026-02-21 17:40:20 作者:

为什么直接用
RSA.Create()
生成的密钥不能跨平台解密

因为 .NET 默认使用的是 Windows CNG(Cryptography Next Generation)实现,生成的密钥默认是

RSACng
类型,私钥导出格式为
PKCS#8
(带密码保护时可能加密),而公钥是
SubjectPublicKeyInfo
格式。但很多其他语言(如 Python 的
cryptography
、Node.js 的
crypto
)默认期望 PEM 封装的
PKCS#1
格式公钥/私钥(即以
-----BEGIN RSA PUBLIC KEY-----
开头)。不转换格式就传给对方,必然解密失败。

实操建议:

导出公钥时,优先用
ExportSubjectPublicKeyInfo()
(对应 PEM 中
-----BEGIN PUBLIC KEY-----
),这是跨语言兼容性最好的选择;
导出私钥时,若需给其他语言用,避免用
ExportPkcs8PrivateKey()
(.NET 6+ 默认),改用
ExportRSAPrivateKey()
得到 PKCS#1 格式(
-----BEGIN RSA PRIVATE KEY-----
),但注意:该方法导出的是未加密私钥,务必确保传输和存储安全;
如果对方坚持要 PKCS#8 无密码私钥(比如 Java 的
PKCS8EncodedKeySpec
),可用
ExportPkcs8PrivateKey()
,再用 OpenSSL 转换:
openssl pkcs8 -topk8 -nocrypt -in key.pk8 -out key.pem

RSA.Encrypt()
报错“Data too large for key size”怎么处理

RSA 本身不能直接加密长数据,它有严格的明文长度限制:对 2048 位密钥,PKCS#1 v1.5 填充下最多加密 245 字节;OAEP 填充下约 190 字节。超过就会抛出

CryptographicException: Data too large for key size

这不是 bug,是 RSA 的数学约束。真实场景中必须分层处理:

用 RSA 加密一个随机生成的 256 位 AES 密钥(即“信封加密”); 用这个 AES 密钥 +
AesGcm
AesCbc
加密实际数据;
把加密后的 AES 密钥和 AES 密文一起发送; 接收方先用 RSA 解密出 AES 密钥,再用它解密数据。

别试图手动分块加密——RSA 分块不仅低效,还破坏语义安全性,且不同填充方式无法简单拼接。

如何安全地序列化和反序列化 RSA 密钥(尤其在 ASP.NET Core 配置中)

密钥不能硬编码,也不该以明文形式存进

appsettings.json
。推荐做法是分离存储:

私钥走操作系统级保护:Windows 用
CngKey.Import()
+ DPAPI,Linux/macOS 用
System.Security.Cryptography.X509Certificates
加载 PFX 并设
X509KeyStorageFlags.EphemeralKeySet
公钥可安全暴露:用
ExportSubjectPublicKeyInfo()
得到字节数组,再转 Base64 存配置,加载时用
ImportSubjectPublicKeyInfo()
还原;
如果必须存私钥字符串(如容器环境),至少用环境变量 + AES-GCM 加密后再存,启动时用 KMS(如 Azure Key Vault、AWS KMS)解密密钥本身; 绝对不要用
ExportParameters(true)
输出
RSAPrivateCrtKey
结构体——它包含所有素数分量,一旦泄露等于私钥彻底暴露。

为什么用
RSASignaturePadding.Pkcs1
签名后,OpenSSL 验证失败

签名算法 ≠ 哈希算法。.NET 的

SignData()
默认只做签名运算,不自动哈希;而 OpenSSL 的
openssl dgst -sha256 -sign
是先哈希再签名。两者行为不一致就会验签失败。

正确对齐方式:

如果对方用
openssl dgst -sha256 -sign key.pem
,你必须在 C# 中先算 SHA256 哈希,再调用
SignHash()
,并指定
RSASignaturePadding.Pkcs1
更推荐统一用
SignData()
+
RSASignaturePadding.Pss
(带盐值),它内部自动哈希(默认 SHA256),且 PSS 是现代标准,OpenSSL 也支持(
openssl pkeyutl -sign -pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss
);
验证时务必用匹配的填充和哈希:PSS 签名必须用
VerifyData()
+
RSASignaturePadding.Pss
,不能混用 Pkcs1。

密钥长度、填充方式、哈希算法这三项必须全部对齐,少一个都会验证失败——而且错误信息往往只报“验证失败”,不会告诉你哪一项不匹配。

相关推荐