如何在C#中解密由Node.js加密的RSA加密字符串?
问题分析与解决:RSA加密解密不匹配导致的InvalidCipherTextException
核心错误原因
Node.js端加密使用的是RSA_PKCS1_OAEP_PADDING(OAEP填充标准),但C#端解密用的是Pkcs1Encoding(对应PKCS#1 v1.5填充),两种填充算法完全不兼容,这是导致解密时抛出InvalidCipherTextException的直接原因。
修正后的C#解密代码
需要改用BouncyCastle的OaepEncoding来匹配Node.js的OAEP填充,同时指定与Node.js一致的SHA256哈希算法:
using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Encodings; using Org.BouncyCastle.OpenSsl; using Org.BouncyCastle.Crypto.Digests; using System.IO; public byte[] DecryptKey(string encryptedKey) { var privateKey = @"-----BEGIN RSA PRIVATE KEY----- ...shortened... -----END RSA PRIVATE KEY-----"; var bytesToDecrypt = Convert.FromBase64String(encryptedKey); // 匹配Node.js的OAEP填充 + SHA256哈希配置 var decryptEngine = new OaepEncoding(new RsaEngine(), new Sha256Digest()); using (var txtreader = new StringReader(privateKey)) { AsymmetricCipherKeyPair keyPair = (AsymmetricCipherKeyPair)new PemReader(txtreader).ReadObject(); decryptEngine.Init(false, keyPair.Private); } // 对称密钥是二进制数据,直接返回字节数组(不要转UTF8,会丢失原始字节) return decryptEngine.ProcessBlock(bytesToDecrypt, 0, bytesToDecrypt.Length); }
关键注意事项
- 填充算法严格一致:OAEP和PKCS#1 v1.5是两种独立的填充标准,两端必须完全匹配,不能混用。
- 对称密钥的正确处理:你生成的32字节对称密钥是纯二进制数据,解密后不要用
Encoding.UTF8.GetString转换(UTF8无法正确解析任意二进制字节),应直接保留字节数组用于后续对称加密操作(比如AES)。 - 密钥配对验证:确保RSA公钥和私钥是配对生成的,密钥长度(如2048/4096位)符合OAEP算法的要求。
可选优化方案
- 改用.NET原生API替代BouncyCastle:如果项目基于.NET Core 3.0+或.NET 5+,可以直接使用原生加密API,无需依赖第三方库:
using System.Security.Cryptography; public byte[] DecryptKeyNative(string encryptedKey, string privateKeyPem) { using var rsa = RSA.Create(); rsa.ImportFromPem(privateKeyPem.ToCharArray()); return rsa.Decrypt(Convert.FromBase64String(encryptedKey), RSAEncryptionPadding.OaepSHA256); }
- Node.js端验证:你的Node.js加密代码逻辑是正确的,可以添加日志输出对称密钥的十六进制值,和解密后的字节数组做对比,排查数据传输过程中是否存在损坏。
内容的提问来源于stack exchange,提问作者BlueManCZ
相关产品推荐
相关产品推荐

