rsacryptoserviceprovider rsa加密需严守四要点:明文≤117字节(utf-8)、密钥xml节点完整且无换行、填充模式加解密一致(false为pkcs#1 v1.5)、base64编解码不可混淆字节与字符串。

RSACryptoServiceProvider 在 .NET 中对字符串做 RSA 加密,不是“直接套函数就能用”的事。明文超长、编码不一致、密钥格式错误、忽略填充模式——这四类问题占了实际报错的 90% 以上。别急着写 Encrypt,先确认你面对的是哪种场景。
明文长度超过 128 - 11 = 117 字节时会抛出 CryptographicException
RSA 加密有硬性长度限制:1024 位密钥对应最大明文为 117 字节(UTF-8 编码下可能更少)。这不是 bug,是 PKCS#1 v1.5 填充规范强制要求的预留空间。一旦 Encoding.UTF8.GetBytes(content).Length > 117,Encrypt 就会炸,错误信息通常是:CryptographicException: Bad Length 或 Key does not exist(后者常是误判)。
- 真实场景中,别用 RSA 加长文本。它本就不该干这事——只加密对称密钥(如 AES 的 32 字节 key)或短 token
- 如果非得传大文本,必须分块:手动切分、逐块加密、拼接 Base64 结果;但注意,
RSACryptoServiceProvider不支持自动分块,得自己控制每块 ≤117 字节 - 更推荐做法:用 AES 加密原文,再用 RSA 加密 AES 的
Key和IV,最后组合传输
FromXmlString 加载密钥失败的常见原因
密钥 XML 格式不对、权限不足、XML 缺失必要节点,都会让 FromXmlString 静默失败或抛出 CryptographicException: Key not valid for use in specified state。
- 公钥 XML 必须含
<modulus></modulus>和<exponent></exponent>;私钥还必须含<p></p><q></q><dp></dp><dq></dq><inverseq></inverseq><d></d>—— 缺一不可 - 不要手动拼接 XML 字符串,尤其注意 Base64 内容换行符(\r\n)会导致解析失败;建议用
rsa.ToXmlString(true/false)生成后原样保存 - .NET Core / .NET 5+ 中
RSACryptoServiceProvider已标记为过时,新项目应改用RSA.Create()+ImportFromPem或ImportParameters,否则在 Linux 容器里大概率加载失败
Encrypt 第二个参数设为 false 意味着使用 PKCS#1 v1.5 填充
这个布尔值不是“要不要填充”,而是指定填充方案:false → PKCS#1 v1.5,true → OAEP。两者不兼容,加密用 false,解密也必须用 false,否则解出来是乱码或直接抛异常。
- PKCS#1 v1.5 是默认且最广泛兼容的,但存在理论上的选择密文攻击风险;OAEP 更安全,但要求 .NET Framework 4.6+ 或 .NET Core 2.1+
- 如果你用 OpenSSL 生成密钥或与 Java 互通,务必确认对方用的也是同一种填充——Java 的
"RSA/ECB/PKCS1Padding"对应 C# 的false,而"RSA/ECB/OAEPWithSHA-1AndMGF1Padding"才对应true - 别把
Encrypt和SignData混用:前者加密原始数据,后者是对哈希值签名,输入内容和语义完全不同
Base64 编码/解码环节最容易漏掉字节对齐
加密后得到的是 byte[],转成字符串必须用 Convert.ToBase64String;解密前必须用 Convert.FromBase64String 还原。中间若混入 URL-safe Base64、截断空格、或用了 UTF-8 编码字符串再转 byte[],就会彻底失败。
- 示例错误写法:
Encoding.UTF8.GetBytes("base64string")—— 这是在对 Base64 字符串本身编码,不是解码 - 正确链路:字符串 → UTF8 bytes →
Encrypt→ cipher bytes →ToBase64String→ 传输;接收端 →FromBase64String→ cipher bytes →Decrypt→ UTF8 bytes →GetString - 特别注意:Windows 下
Notepad粘贴 Base64 可能自动换行,导致解码失败;建议用string.Replace("\r\n", "")清洗
真正麻烦的从来不是调用几行代码,而是密钥怎么存、谁生成、跨平台怎么验、失败时看哪条错误堆栈。RSA 不是黑盒,每个参数背后都是密码学约束;跳过这些细节,哪怕跑通一次,上线后也会在某个字符集、某次部署、某个 JDK 版本上突然卡住。











