使用C#实现AES-RSA加解密对接FastSpring遇错求助
关于FastSpring加密载荷的RSA加密解密问题
问题背景
项目向FastSpring发送加密载荷的流程如下:
- 生成2048位RSA公私证书对,将公证书上传至FastSpring;
- 使用OpenSSL生成密钥对的命令:
openssl genrsa -out privatekey.pem 2048openssl req -new -key privatekey.pem -x509 -days 3650 -out publiccert.pem - 随机生成16字节AES密钥,用该密钥加密载荷,再用私钥加密AES密钥,将加密后的载荷和AES密钥发送给FastSpring;
- FastSpring用已上传的公证书解密AES密钥,再解密载荷。
我的AES密钥加密代码(C#)
string privateKeyText = File.ReadAllText(PathToPrivateKey); using RSA privateRsa = RSA.Create(); privateRsa.ImportFromPem(privateKeyText.ToCharArray()); byte[] bytesToEncrypt = Encoding.UTF8.GetBytes(textToEncrypt); //AES Key byte[] encryptedAesKey = rsa.Encrypt(bytesToEncrypt, RSAEncryptionPadding.OaepSHA256);
本地测试解密代码及错误
测试代码:
using var publicX509 = new X509Certificate2(PathToCertificate); RSA publicRsa = publicX509.GetRSAPublicKey(); byte[] decryptedBytes = rsa.Decrypt(encryptedAesKey, RSAEncryptionPadding.OaepSHA256); string decryptedAesKey = Encoding.UTF8.GetString(decryptedBytes);
错误信息:
WindowsCryptographicException: Key does not exist. at System.Security.Cryptography.RSACng.EncryptOrDecrypt(SafeNCryptKeyHandle key, ReadOnlySpan`1 input, AsymmetricPaddingMode paddingMode, Void* paddingInfo, Boolean encrypt) at System.Security.Cryptography.RSACng.EncryptOrDecrypt(Byte[] data, RSAEncryptionPadding padding, Boolean encrypt) at System.Security.Cryptography.RSACng.Decrypt(Byte[] data, RSAEncryptionPadding padding) at UserQuery.DecryptData(Byte[] dataToDecrypt, RSA rsa), line 37 at UserQuery.Main(), line 20
疑问
常规RSA是公钥加密、私钥解密,但FastSpring文档显示私钥加密后用公钥解密可行,请问该方式是否有效?若有效,错误原因是什么?
FastSpring支持团队提供的实现代码(C#)
public static string CreateSecureLoad(string clearText, ref byte[] generatedAesKey) { RijndaelManaged cryptoAlgo = new RijndaelManaged { Padding = PaddingMode.PKCS7, Mode = CipherMode.ECB, KeySize = 128, BlockSize = 128 }; generatedAesKey = cryptoAlgo.Key; var clearTextArrary = Encoding.UTF8.GetBytes(clearText); var encryptor = cryptoAlgo.CreateEncryptor(); using (MemoryStream msEncryprt = new MemoryStream()) { using (CryptoStream csEncrypt = new CryptoStream(msEncryprt, encryptor, CryptoStreamMode.Write)) { csEncrypt.Write(clearTextArrary); csEncrypt.FlushFinalBlock(); var cipher = msEncryprt.ToArray(); return Convert.ToBase64String(cipher); } } return ""; } public static string CreateSecureKey(byte[] aesKey, string privateKeyPEM) { var encryptEngine = new Pkcs1Encoding(new RsaEngine()); using (var textReader = new StreamReader(privateKeyPEM)) { var pemReader = new PemReader(textReader); var keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject(); encryptEngine.Init(true, keyPair.Private); } var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(aesKey, 0, aesKey.Length)); return encrypted; } public static string CreateSecureKeyFromPEM(byte[] aesKey, string privateKeyPEM) { var encryptEngine = new Pkcs1Encoding(new RsaEngine()); using (TextReader textReader = new StringReader(privateKeyPEM)) { var pemReader = new PemReader(textReader); var keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject(); encryptEngine.Init(true, keyPair.Private); } var encrypted = Convert.ToBase64String(encryptEngine.ProcessBlock(aesKey, 0, aesKey.Length)); return encrypted; }
解答
1. 私钥加密、公钥解密的有效性
这种方式是有效的,本质是利用RSA非对称性实现身份验证:只有持有私钥的一方能生成加密内容,持有公钥的一方可以验证并解密,确认内容来自私钥持有者,符合FastSpring的安全校验需求。
2. 错误原因分析
你的代码存在两个核心问题:
- API使用逻辑错误:.NET内置的
RSA.Encrypt方法仅用于公钥加密,即便传入私钥实例,该方法依然会按公钥加密逻辑执行,生成的密文无法用公钥解密;而RSA.Decrypt仅用于私钥解密,用公钥实例调用会直接抛出密钥不存在的错误。 - 填充方式不匹配:FastSpring提供的代码使用PKCS#1 v1.5填充(通过
Pkcs1Encoding实现),而你使用的是OAEP-SHA256填充,两者不兼容,这是FastSpring无法解密的直接原因。
3. 修复方案
- 直接采用FastSpring提供的代码:该代码依赖BouncyCastle库,使用其API实现私钥加密、公钥解密的逻辑,且填充方式与FastSpring端完全匹配。
- 若不想引入第三方库,可通过RSA签名逻辑模拟:用私钥对AES密钥生成签名(本质是带PKCS#1填充的加密),用公钥验证签名并确认内容有效性,但.NET没有直接提取原始内容的API,如需还原AES密钥仍建议使用BouncyCastle。
内容的提问来源于stack exchange,提问作者Joseph Johnson
相关产品推荐
相关产品推荐

