RSA密钥跨平台解密失败主因是格式不兼容:.NET默认导出PKCS#8私钥和SubjectPublicKeyInfo公钥,而Python/Node.js等常需PKCS#1格式(-----BEGIN RSA PUBLIC KEY-----);应导出时选ExportSubjectPublicKeyInfo()和ExportRSAPrivateKey()以提升兼容性。

为什么直接用 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。
密钥长度、填充方式、哈希算法这三项必须全部对齐,少一个都会验证失败——而且错误信息往往只报“验证失败”,不会告诉你哪一项不匹配。










